2015-03-31 36 views
13

Mam modelu Edge należącego do innego modelu Node dwa razy przez różnych kluczy obcych:Szyny kwerendy dołączyć tabelę skojarzeń z aliasu

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

I chcę wykonać kwerendy przy użyciu ActiveRecord:

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

mogę znaleźć drogę do dołączenia do asocjacji z zastosowaniem .joins() metody:

Edge.joins(:first) 

Ale to tworzy zapytanie przy użyciu nazwy tabeli, a nie nazwy powiązania, więc w metodzie .where() muszę jawnie używać nazwy tabeli, która przerywa asocjację abstrakcji.

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

Mogę również jawnie użyć zapytania SQL w .joins() sposobu definiowania modelu alias:

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

Ale to łamie nawet więcej abstrakcji.

Myślę, że powinien istnieć sposób automatycznego definiowania aliasu tabeli podczas łączenia. A może sposób na samodzielne napisanie takiej funkcji. Coś jak:

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 

Ale nie mogłem znaleźć żadnych informacji o dostępie do informacji o konkretnej relacji jak to nazwa, klucz obcy, itp Więc jak mogę to zrobić?

Wydaje mi się również dziwne, że taka oczywista cecha jest tak skomplikowana, nawet gdy Rails jest już na swojej czwartej wersji głównej. Może coś mi brakuje?

Odpowiedz

5

Jeśli chodzi o Rails 4.2.1, uważam, że po prostu nie można podać aliasu przy użyciu joins z ActiveRecord.

Jeśli chcesz zapytać brzegi przez pierwszy węzeł, można to zrobić tak jak stwierdził:

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

Ale jeśli masz do zapytania przy użyciu obu węzłów, można nadal korzystać joins takiego:

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