1

我在访问 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 模型的任何属性。

在 Rails3 之前,我曾经做一个 find_by_sql 并且可以在返回的哈希中轻松访问两个连接表的属性,但是我根本无法让 Rails3 向我显示连接地址表中的属性。

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

4

2 回答 2

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,除了添加加入模型外,还将在 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)"
于 2010-10-21T11:51:05.500 回答
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
于 2011-01-07T04:15:20.667 回答