2013-02-07 67 views
1

我用的has_many通過首次工作,儘管大量的閱讀在這裏和guide我不理解對通過訪問表屬性的正確方法。我的表與另一篇文章中的示例相同。Rails 3中的has_many:通過訪問屬性

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 

假設合作者表中有附加屬性,說hours_spent,什麼是找到合作者表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個查詢返回一組。所以我想我需要某種唯一性約束,但這必須是屬於鍵的兩種類型的複合鍵。這甚至有可能嗎?有沒有更好的模型結構?

感謝這麼多的快速和有益的反應!

+3

請參閱'has_one'而不是'has_many'。 – meagar

回答

0

實施在此之後,我發現,我認爲我有正確的關係設置,我只好用的has_many:雖然因爲用戶可以有許多產品,它需要:通過,因爲在協作者表上有其他屬性。問題的關鍵在於如何實現每個用戶/產品對的唯一一個協作者記錄,然後如何保證我獲得了該記錄。至此,我發現的答案是必須在代碼中完成。

爲了確保只有一個記錄對於每一對,我用

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

然後,爲了以防萬一,我找到合適的記錄,我有一個範圍

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

如果有人有一個更優雅的解決方案,或者只是想改善這個問題,請張貼,我會改變你的選擇答案。

0

有可能是每對單個數據庫行,但考慮到單個用戶時,該用戶可以關聯到很多產品,因此用戶可以在合作者表中的許多行。同樣,在考慮單個產品時,該產品可以與許多用戶關聯,因此產品在協作者表中可以有多行。

此外,如果您只想要第一個協作者花費的小時數,則可以不使用user.collaborators[0].hours_spent,而使用user.collaborators.first.try(:hours_spent)(可能返回null)。

如果一個用戶只能有一個單一產品和單一的產品只能有一個用戶,然後切換的has_many對HAS_ONE的一切。

更新:前面的是答案,這已經被通過的意見澄清了原來的問題。請參閱評論的詳細內容,並參閱Peter提供的其他答案的評論。

+0

用戶可以有很多產品,產品可以有很多用戶。但是,特定用戶和特定產品之間應該只有一次合作。 – Questor

+0

如果我理解正確,user.collaborators.first.try(:hours_spent)會爲我提供該用戶的第一個協作。是否有一些軌道魔法使其成爲該用戶針對特定產品的首次合作? – Questor

+0

好吧,如果一個用戶只能有一個產品,那麼在用戶上,has_many ...和has_many ...:through應該是has_one ...和has_one ...:通過哪個@meagar和I告訴你。然後花費的時間將是'user.collaborator.try(:hours_spent)'。如果單個產品只能與單個用戶相關聯,則與產品一樣,但我懷疑是這種情況。 –

0

也許你應該使用has_and_belongs_to_many。如果您的協作者僅用於在用戶和產品之間建立鏈接而沒有更多字段。

class Product < ActiveRecord::Base 
     has_and_belongs_to_many :users 
    end 

    class User < ActiveRecord::Base 
     has_and_belongs_to_many :products 
    end 

的beetween遷移將是:

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