Как получить доступ к атрибутам объединенной таблицы в Rails3? - PullRequest
1 голос
/ 21 октября 2010

У меня проблемы с доступом к атрибутам объединения в Rails3.

Существует две модели / таблицы: Place и Address.В одном месте может быть много адресов (например, конкретный адрес улицы, «угол» адреса и т. Д.).По историческим причинам таблицы не соответствуют стандартным соглашениям Rails:

class Place < ActiveRecord::Base
 set_table_name :PLACE
 set_primary_key :PLACE_ID
 has_many :addresses, :class_name => "Address", :foreign_key => :PLACE_ID
end

и

class Address < ActiveRecord::Base
 set_table_name :ADDRESS
 set_primary_key :ADDRESS_ID
 belongs_to :place, :foreign_key => "PLACE_ID"
end

Я пытаюсь получить все адреса для одного конкретного места:

pa = Place.joins(:addresses).where(:place_id => 68)

Сгенерированный SQL выглядит нормально:

pa.to_sql

"SELECT [PLACE].* FROM [PLACE] INNER JOIN [ADDRESS] ON [ADDRESS].[PLACE_ID] = [PLACE].[PLACE_ID] WHERE ([PLACE].[place_id] = 68)"

Возвращенное отношение также имеет правильный размер, поскольку с этим конкретным местом связано 6 адресов:

irb(main):050:0> pa.size
=> 6

Однако возвращенное отношение pa содержит только атрибуты модели Place, оно не содержит никаких атрибутов модели Address.

Pre Rails3 Я использовал для выполнения find_by_sql и мог получить доступ к атрибутам двух соединенныхлегко возвращать таблицу в возвращенном хэше, однако я просто не могу заставить Rails3 открыть мне атрибуты из объединенной таблицы адресов.

Мне, должно быть, здесь не хватает чего-то очень простого - кто-нибудь захочет указать мне на это?

Ответы [ 2 ]

4 голосов
/ 21 октября 2010

Вы ищете включений вместо объединений. Это будет делать именно то, что вы хотите.

pa = Place.includes(:addresses).where(:place_id => 68)

Если вы хотите заказать по адресу address.street_name в своем комментарии к ответу captaintokyo. Вы можете сделать затем добавить заказ, как это:

pa = Place.includes(:addresses).where(:place_id => 68).order(:addresses => :street_name)

Разница между двумя включениями и объединениями заключается в том, что joins присоединит предоставленные модели к произведенному запросу для сопоставления в предложении where. В отличие от includes, который, помимо добавления присоединения к модели, будет также включать поля этой модели в операторе select.

Итак, резюмируем:

Place.includes(:addresses).where(:place_id => 68)

производит это:

"SELECT [PLACE].*, [ADDRESS].* FROM [PLACE] INNER JOIN [ADDRESS] ON [ADDRESS].[PLACE_ID] = [PLACE].[PLACE_ID] WHERE ([PLACE].[place_id] = 68)"

, а

Place.joins(:addresses).where(:place_id => 68)

производит это:

"SELECT [PLACE].* FROM [PLACE] INNER JOIN [ADDRESS] ON [ADDRESS].[PLACE_ID] = [PLACE].[PLACE_ID] WHERE ([PLACE].[place_id] = 68)"
0 голосов
/ 07 января 2011

То, что вам нужно, так же, как

pa = Place.joins(:addresses).where(:place_id => 68).select('PLACE.*, ADDRESS.*')

и тогда вы получите все атрибуты в па для этих двух таблиц.

Но мне интересно, есть ли лучший дизайн для вас:

class Place < ActiveRecord::Base
 set_table_name :PLACE
 set_primary_key :PLACE_ID
 has_many :addresses, :class_name => "Address", :foreign_key => :PLACE_ID
end

class Address < ActiveRecord::Base
 set_table_name :ADDRESS
 set_primary_key :ADDRESS_ID
 belongs_to :place, :foreign_key => "PLACE_ID"

 scope :with_place, lambda {|place_id| joins(:place).where(:place_id => place_id).select('ADDRESS.*, PLACE.*')}
end

addresses = Address.with_place(68)

или просто используйте функцию делегата, если вам нужно одновременно использовать экземпляр Place

class Address < ActiveRecord::Base
 set_table_name :ADDRESS
 set_primary_key :ADDRESS_ID
 belongs_to :place, :foreign_key => "PLACE_ID"

 delegate :any_place_attribute, :to => :place
end

address = Address.find(x)
address.any_place_attribute #you can access PLACE table attribute now
...