如何在Rails3中访问连接表属性?

时间:2010-10-21 11:20:51

标签: sql ruby join ruby-on-rails-3 relation

我无法在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向我显示 已加入的地址表中的属性。

我必须在这里遗漏一些非常基本的东西 - 有人想指出我吗?

2 个答案:

答案 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