valores tipos tabla listado funciones create con basicas avg agregadas sql ruby-on-rails postgresql activerecord arel

tipos - listado de funciones en sql server



Cómo hacer que el setter de atributos envíe valor a través de la función de SQL (1)

Estoy tratando de hacer que un setter de atributos en un modelo ActiveRecord ajuste su valor en la función text2ltree () postgres antes de que rails genere su consulta sql.

Por ejemplo,

post.path = "1.2.3" post.save

Debería generar algo así como

UPDATE posts SET PATH=text2ltree(''1.2.3'') WHERE id = 123 # or whatever

¿Cuál es la mejor manera de hacer esto?


EDITAR: para lograr exactamente lo que estás buscando arriba, lo usarías para anular el setter predeterminado en tu archivo de modelo:

def path=(value) self[:path] = connection.execute("SELECT text2ltree(''#{value}'');")[0][0] end

Entonces el código que tienes arriba funciona.

Estoy interesado en aprender más sobre el funcionamiento interno de ActiveRecord y sus bases de metaprogramación impenetrables, así que como ejercicio intenté lograr lo que describiste en tus comentarios a continuación. Aquí hay un ejemplo que funcionó para mí (esto es todo en post.rb):

module DatabaseTransformation extend ActiveSupport::Concern module ClassMethods def transformed_by_database(transformed_attributes = {}) transformed_attributes.each do |attr_name, transformation| define_method("#{attr_name}=") do |argument| transformed_value = connection.execute("SELECT #{transformation}(''#{argument}'');")[0][0] write_attribute(attr_name, transformed_value) end end end end end class Post < ActiveRecord::Base attr_accessible :name, :path, :version include DatabaseTransformation transformed_by_database :name => "length" end

Salida de la consola:

1.9.3p194 :001 > p = Post.new(:name => "foo") (0.3ms) SELECT length(''foo''); => #<Post id: nil, name: 3, path: nil, version: nil, created_at: nil, updated_at: nil>

En la vida real, supongo que querrá include el módulo en ActiveRecord :: Base, en un archivo en algún lugar anterior de la ruta de carga. También tendría que manejar adecuadamente el tipo de argumento que está pasando a la función de base de datos. Finalmente, me enteré de que connection.execute está implementado por cada adaptador de base de datos, por lo que la forma de acceder al resultado puede ser diferente en Postgres (este ejemplo es SQLite3, donde el conjunto de resultados se devuelve como una matriz de hashes y la clave de la primera el registro de datos es 0].

Esta publicación del blog fue increíblemente útil:

http://www.fakingfantastic.com/2010/09/20/concerning-yourself-with-active-support-concern/

como era la guía de Rails para la creación de plugins:

http://guides.rubyonrails.org/plugins.html

Además, por lo que vale, creo que en Postgres aún lo haría utilizando una migración para crear una regla de reescritura de consultas, pero esto resultó en una gran experiencia de aprendizaje. Espero que funcione y pueda dejar de pensar en cómo hacerlo ahora.