的has_many:通过:你如何访问连接表的属性? [英] has_many :through : How do you access join table attributes?

查看:251
本文介绍了的has_many:通过:你如何访问连接表的属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在轨道4以下机型使用一个简单的has_many:通过关联:

I have the following models in Rails 4 with a simple has_many :through association:

class Model < ActiveRecord::Base
  has_many :model_options
  has_many :options, through: :model_options
end

class Option < ActiveRecord::Base
  has_many :model_options
  has_many :models, through: :model_options
end

class ModelOption < ActiveRecord::Base
  belongs_to :model
  belongs_to :option
end

我希望能够遍历模型实例的选项:

I want to be able to iterate over a Model instance's Options:

  model = Model.find.first
  model.options.each {}

和访问连接表的属性。

在Rails 3中,你可以这样做:

In Rails 3 you could do this:

class Model < ActiveRecord::Base
  has_many :model_options
  has_many :options, through: :model_options , select: 'options.*, model_options.*'
end

但选择:是去precated这将产生一个去precation警告

But select: is deprecated and this produces a deprecation warning.

这就是说,生成的SQL包含链接表中的数据:

That said, the SQL generated contains the link table data:

SELECT options.*, model_options.* FROM "options"
INNER JOIN "model_options" ON "options"."id" = "model_options"."option_id"
WHERE "model_options"."model_id" = $1 ORDER BY "options".name ASC  [["model_id", 1]]

不过从model.options通过AR返回集合中删除链接表中的数据。

But the collection returned by AR from model.options removes the link table data.

要删除德precations Rails中4警告,仍然产生相同的SQL,我这样做:

To remove the deprecations warning in Rails 4, and still produce the same SQL, I did this:

class Model < ActiveRecord::Base
  has_many :model_options
  has_many :options, -> { select('options.*, model_options.*') }, through: :model_options
end

所以,查询是正确的,但我在努力寻找访问链接表数据的正确方法。

So, the query is correct, but I am struggling to find the correct way to access the link table data.

我已经尝试了各种方式:

I have tried various ways:

 model options
 model.options.joins(:model_options)
 model.options.select('options.*, model_options.*')
 model.model_options.joins(:option)
 ...

没有包括连接表的数据。

None include the join table data.

感谢。

推荐答案

对于你想要达到什么样的答案可能会有所不同。你想找回这些属性,或将其用于查询?

The answer may be different regarding what you want to achieve. Do you want to retrieve those attributes or to use them for querying ?

ActiveRecord的是有关映射表行的对象,所以你不能从一个对象的属性到其他。

ActiveRecord is about mapping table rows to objects, so you can't have attributes from one object into an other.

让使用更具体的例子:有房子,人与狗。一个人belongs_to的房子。狗belongs_to的一个人。房子有很多人。一所房子经过的人有许多狗。

Let use a more concrete example : There are House, Person and Dog. A person belongs_to house. A dog belongs_to a person. A house has many people. A house has many dogs through people.

现在,如果你要检索的狗,你不要指望在它的人的属性。这是没有意义有狗属性的car_id属性。

Now, if you have to retrieve a dog, you don't expect to have person attributes in it. It wouldn't make sense to have a car_id attribute in dog attributes.

话虽这么说,这不是一个问题:你真正想要的,我想,是为了避免大量的数据库查询的,在这里。 Rails有你的背部上:

That being said, it's not a problem : what you really want, I think, is to avoid making a lot of db queries, here. Rails has your back on that :

# this will generate a sql query, retrieving options and model_options rows
options = model.options.includes( :model_options )

# no new sql query here, all data is already loaded
option = options.first

# still no new query, everything is already loaded by `#includes`
additional_data = option.model_options.first

编辑:它会表现这样的控制台。在实际应用code,SQL查询将被解雇的第二个命令,因为第一个没有使用的结果(SQL查询被触发,只有当我们需要它的结果)。但是,这并没有改变任何东西。它只是轰出单时间

Edit : It will behaves like this in console. In actually app code, the sql query will be fired on second command, because first one didn't use the result (the sql query is triggered only when we need its results). But this does not change anything here : it's only fired a single time.

#包括做到了这一点:加载结果集中从外部表中的所有属性。然后,一切都被映射到有一个有意义的面向对象的再presentation。

#includes does just that : loading all attributes from a foreign table in the result set. Then, everything is mapped to have a meaningful object oriented representation.

如果你想基于这两个选项,ModelOptions查询,你将不得不使用 #references 。让说你的ModelOption有一个主动属性:

If you want to make query based on both Options and ModelOptions, you'll have to use #references. Let say your ModelOption has an active attribute :

# This will return all Option related to model 
# for which ModelOption is active
model.options.references( :model_options ).where( model_options: { active: true })

结论

#包括将加载在结果所有外国行设置,使您可以在以后使用它们,无需进一步查询数据库。 #references 也将让您使用表中查询。

Conclusion

#includes will load all foreign rows in result set so that you can use them later without further querying the database. #references will also allow you to use the table in queries.

在任何情况下都会有一个包含从其他模型数据的对象,但是这是一件好事。

In no case will you have an object containing data from an other model, but that's a good thing.

这篇关于的has_many:通过:你如何访问连接表的属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆