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

发布于 2024-09-28 10:29:36 字数 1074 浏览 10 评论 0原文

我在访问 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 向我显示 来自连接的地址表的属性。

我一定错过了一些非常基本的东西 - 有人愿意向我指出吗?

I am having trouble accessing the attributes of a join in Rails3.

There is two models/tables : Place and Address. One place can have many addresses (i.e. a specific street address, a "corner of" address, etc.). For historical reasons, the tables do not follow standard Rails conventions:

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

and

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

I am trying to get all the addresses for one particular place:

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

The SQL that is generated looks fine:

pa.to_sql

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

The returned relation also has the right size, as that particular place has 6 addresses associated with it:

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

However, the returned relation pa only contains the attributes of the Place model, it doesn't contain any attributes of the Address model.

Pre Rails3 I used to do a find_by_sql and could access the attributes of the two joined table easily in the returned Hash, however I simply cannot get Rails3 to reveal to me the
attributes from the joined Address table.

I must be missing something very basic here - anyone care to point it out to me ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

笑忘罢 2024-10-05 10:29:36

您正在寻找包含而不是联接。这将完全符合您的要求。

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

如果您想通过在captaintokyo的答案评论中的address.street_name订购。然后,您可以添加如下顺序:

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

两个包含和连接之间的区别在于,连接会将提供的模型连接到生成的查询,以便在 where 子句中进行匹配。与 includes 相反,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)"

You're looking for includes instead of joins. This will do exactly what you want.

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

If you want to order by address.street_name in your comment to captaintokyo's answer. You can do then add an order like this:

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

The difference between the two includes and joins is that joins will join the supplied models to the produced query for the sake matching in a where clause. As opposed to includes which, in addition to adding joining the model, will also include that model's fields in the select statement.

So to recap:

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

produces this:

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

while

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

produces this:

"SELECT [PLACE].* FROM [PLACE] INNER JOIN [ADDRESS] ON [ADDRESS].[PLACE_ID] = [PLACE].[PLACE_ID] WHERE ([PLACE].[place_id] = 68)"
陌上青苔 2024-10-05 10:29:36

你所需要的 arel 方式就像这样

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

What you need in arel way is just like

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

and then you will get all the attributes in pa for these two tables.

But I am wondering if there is a better design for you:

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)

or just use the delegate function if you need to use Place instance at the same time

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文