1

我第一次使用 has_many through,尽管在此处和指南中阅读了大量内容,但 我不了解访问通过表上的属性的正确方法。我的表格与另一篇文章中的示例相同。

    class Product < ActiveRecord::Base
       has_many :collaborators
       has_many :users, :through => :collaborators
    end

    class User < ActiveRecord::Base
       has_many :collaborators
       has_many :products, :through => :collaborators
   end

   class Collaborator < ActiveRecord::Base
      belongs_to :product
      belongs_to :user
   end

假设 collaborators 表具有附加属性,例如 hours_spent,那么从特定用户和产品的 collaborator 表中找到 hours_spent 的正确方法是什么?

当我通过产品找到我的用户并像在

    @product.users.each do |user| 

这似乎有效

    user.collaborator[0].hours_spent

我得到了正确的值,但由于每个用户/产品对应该只有一个合作者记录,所以索引让我失望,让我觉得我做错了什么。

感谢您的阅读!

编辑

也许我没有通过概念获得 has_many 。也许一个 MySQL 示例会有所帮助。

我在想的是,如果我这样做了

    SELECT * FROM collaborators where user_id = 1;

我希望结果是一组(零个或更多)。相似地

    SELECT * FROM collaborators where product_id = 1;

也会给我一套,但是

    SELECT * FROM collaborators where user_id = 1 and product_id = 1;

最多会给出 1 行。

如果我理解正确,所有 3 个查询都会返回一个集合。所以我想我需要某种唯一性约束,但这必须是一个复合键,在两个属于键上。这甚至可能吗?有没有更好地模拟这个的结构?

非常感谢您的快速和有用的回复!

4

3 回答 3

0

There may be a single database row per pair, but when considering a single user, that user can be associated to many products, so a user can have many rows in the collaborators table. Similarly, when considering a single product, that product can be associated to many users, so a product can have many rows in the collaborators table.

Also, instead of using user.collaborators[0].hours_spent, use user.collaborators.first.try(:hours_spent) (which may return null), if you only want the first collaborator's hours spent.

If a single user can only have one single product and a single product can only have a single user, then switch the has_many's to has_one's for everything.

Update: The preceding is the answer to the original question which has since been clarified via comments. See comments for detail and see comments on other answer by Peter.

于 2013-02-07T18:19:00.567 回答
0

Perhaps you should use has_and_belongs_to_many. If your Collaborator is used only to make link between User and Product without having more fields.

    class Product < ActiveRecord::Base
       has_and_belongs_to_many :users
    end

    class User < ActiveRecord::Base
       has_and_belongs_to_many :products
   end

The beetween migration would be:

class CreateUsersProducts < ActiveRecord::Migration
  def change
    create_table "users_products", :id => false do |t|
      t.integer :user_id
      t.integer :product_id
    end
  end
end
于 2013-02-08T01:44:30.027 回答
0

After implementing this, what I found was that I think I had the correct relationships setup, I had to use the has_many :though as users could have many products, and it needed to be :through because there are additional attributes on the collaborator table. The sticking point was how to get there to only be a single Collaborator record for each user/product pair, and then how do I guarantee I got it. And to this point the answer I've found is it has to be done in code.

To make sure there is only a single record for each pair, I used

class Collaborator < ActiveRecord::Base
  validates :product_id, :presence => true,  :uniqueness => {:scope => [:user_id], :message => "This is a duplicate join"}

And then to make doubly sure I'm finding the right record, I have a scope

 scope :collaboration_instance, lambda {|p_id, u_id| where("collaborations.product_id = ? && collaborations.user_id = ?", p_id, u_id)}

If someone has a more elegant solution, or just wants to improve this one, please post and I will change yours to the selected answer.

于 2013-04-17T16:17:25.127 回答