2015-03-31 11 views
13

Ich habe ein Modell Edge die Node zweimal durch verschiedene Fremdschlüssel zu dem anderen Modell gehört:Rails Abfrage mit Alias-Zuordnungstabelle beitreten

def Edge < ActiveRecord::Base 
    belongs_to :first, class_name: 'Node' 
    belongs_to :second, class_name: 'Node' 
end 

Und ich mag diese Abfrage mit Active auszuführen:

SELECT * FROM edges INNER JOIN nodes as first ON first.id = edges.first_id WHERE first.value = 5 

fand ich die Art und Weise Vereinigung mit .joins() Verfahren beizutreten:

Edge.joins(:first) 

Aber dies erzeugt Abfrage mit einem Tabellennamen, nicht ein Verbandsname, so in .where() Methode muss ich explizit Tabellenname verwenden, die Association Abstraktion bricht.

Edge.joins(:first).where(nodes: {value: 5}) 

Ich kann auch explizit SQL-Abfrage in .joins() Methode verwenden, um Modell-Alias ​​zu definieren:

Edge.joins('INNER JOIN nodes as first ON nodes.id = edges.first_id') 

Aber das bricht noch mehr Abstraktion.

Ich denke, es sollte die Möglichkeit geben, Tabellenalias automatisch bei Join zu definieren. Oder vielleicht eine Möglichkeit, solche Funktionen selbst zu schreiben. Etwas wie:

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 

Aber ich konnte keine Informationen über den Zugriff auf Informationen über bestimmte Beziehung, wie es der Name, die Fremdschlüssel finden, usw. Also, wie kann ich es tun?

Auch scheint mir seltsam, dass so offensichtlich Feature ist so kompliziert, auch durch Rails ist auf seiner 4. Hauptversion bereits. Vielleicht vermisse ich etwas?

Antwort

5

Wie für Rails 4.2.1, ich glaube, Sie können nur einen Alias ​​bei Verwendung joins von ActiveRecord nicht bereitstellen.

Wenn Sie Kanten abfragen durch den ersten Knoten möchten, können Sie es tun, so wie du gesagt:

Edge.joins(:first).where(nodes: {value: 1}) 
SELECT "edges".* FROM "edges" INNER JOIN "nodes" ON "nodes"."id" = "edges"."first_id" WHERE "nodes"."value" = 1 

Aber wenn Sie beide Knoten mit abzufragen, können Sie immer noch joins wie folgt verwenden:

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