ruby on rails - rails - Tabla de asociación de consultas de carriles con alias
scope rails (1)
Tengo un modelo Edge
que pertenece al otro modelo Node
dos veces a través de diferentes claves foráneas:
def Edge < ActiveRecord::Base
belongs_to :first, class_name: ''Node''
belongs_to :second, class_name: ''Node''
end
Y quiero realizar esta consulta usando ActiveRecord:
SELECT * FROM edges INNER JOIN nodes as first ON first.id = edges.first_id WHERE first.value = 5
Encontré la manera de unirme a la asociación usando el método .joins()
:
Edge.joins(:first)
Pero esto produce una consulta usando un nombre de tabla, no un nombre de asociación, así que en el método .where()
tengo que usar explícitamente el nombre de la tabla que rompe la abstracción de la asociación.
Edge.joins(:first).where(nodes: {value: 5})
También puedo usar explícitamente la consulta SQL en el método .joins()
para definir el alias del modelo:
Edge.joins(''INNER JOIN nodes as first ON nodes.id = edges.first_id'')
Pero esto rompe aún más abstracción.
Creo que debería haber una manera de definir automáticamente alias de tabla en join. O tal vez una forma de escribir esa función por mi cuenta. Algo como:
def Edge < ActiveRecord::Base
...
def self.joins_alias
# Generate something like
# joins("INNER JOIN #{relation.table} as #{relation.alias} ON #{relation.alias}.#{relation.primary_key} = #{table}.#{relation.foreign_key}")
end
end
Pero no pude encontrar ninguna información sobre el acceso a la información sobre una relación específica como su nombre, clave externa, etc. Entonces, ¿cómo puedo hacerlo?
También me parece extraño que una característica tan obvia sea tan complicada incluso a pesar de que Rails ya está en su cuarta versión principal. Tal vez me estoy perdiendo algo?
En cuanto a Rails 4.2.1, creo que simplemente no puede proporcionar un alias cuando usa joins
de ActiveRecord.
Si desea consultar bordes por el primer nodo, puede hacerlo tal como lo indicó:
Edge.joins(:first).where(nodes: {value: 1})
SELECT "edges".* FROM "edges" INNER JOIN "nodes" ON "nodes"."id" = "edges"."first_id" WHERE "nodes"."value" = 1
Pero si tiene que consultar utilizando ambos nodos, puede seguir utilizando joins
así:
Edge.joins(:first, :second).where(nodes: {value: 1}, seconds_edges: {value: 2})
SELECT "edges".* FROM "edges" INNER JOIN "nodes" ON "nodes"."id" = "edges"."first_id" INNER JOIN "nodes" "seconds_edges" ON "seconds_edges"."id" = "edges"."second_id" WHERE "nodes"."value" = 1 AND "seconds_edges"."value" = 2