我无法在Rails3中访问联接的属性。
有两个模型/表格:地点和地址。一个地方可以有许多地址(即特定的街道地址,“地址的角落”等)。由于历史原因,表格不遵循标准的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并且可以在返回的Hash中轻松访问两个连接表的属性,但是我根本无法让Rails3向我显示 已加入的地址表中的属性。
我必须在这里遗漏一些非常基本的东西 - 有人想指出我吗?
答案 0 :(得分:4)
您正在寻找包含而不是加入。这将完全符合您的要求。
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
相反,Place.includes(:addresses).where(:place_id => 68)
除了添加模型之外,还将在select语句中包含该模型的字段。
所以回顾一下:
"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)"
产生这个:
{{1}}
答案 1 :(得分:0)
你需要的东西就像
pa = Place.joins(:addresses).where(:place_id => 68).select('PLACE.*, ADDRESS.*')
然后你将获得这两个表的pa中的所有属性。
但我想知道你是否有更好的设计:
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