2014-04-15 91 views
0

我現在有這些模型:多個關聯爲了同一個模型用了許多通過

class Base < ActiveRecord::Base 
    has_many :base_tags 
    has_many :tags, through: :base_tags 
    has_many :primary_tags, through: :base_tags, class_name: 'Tag', source: :tag, conditions: ['base_tags.primary = ?', true] 
    has_and_belongs_to_many :channels 
end 

class Tag < ActiveRecord::Base 
    has_many :base_tags 
    has_many :bases, through: :base_tags 
end 

class BaseTag < ActiveRecord::Base 
    belongs_to :base 
    belongs_to :tag 
end 

我竭力要實現對示範基地的主要標籤。在基本實例調用#primary_tags retuns正確的記錄,但同時要創建/更新的記錄:

Base.create({tag_ids: [1,2], primary_tag_ids: [1]}) 

我遇到了以下錯誤:

ActiveRecord::RecordNotUnique 

Mysql2::Error: Duplicate entry '1-2' for key 'index_bases_tags_on_base_id_and_tag_id': INSERT INTO `base_tags` (`base_id`, `primary`, `tag_id`) VALUES (1, 0, 2) 

的ActiveRecord試圖創建primary_tag_id與tag_ids有相同的關聯關係,當它真的應該更新關係並且主屬性應該是1.

是否有任何方法讓ActiveRecord可以很好地播放?我想象我的has_many:primary_tags關係不正確。

+0

你想用primary_tags屬性來完成什麼? – Lumbee

+0

我希望primary_tags關聯是所有適當方法的標籤子集。所以我可以調用base.primary_tags獲取主標籤數組或base.primary_tags =將其設置爲其他值。 – Tom

回答

2

我覺得有兩個問題。首先,如果使用字符串形式的條件,則activerecord不能解析該sql片段並理解它應該設置的屬性。

其次,因爲這是一個經歷了許多,我覺得這些條件必須在加入模型關聯

,象這樣

class Base < ActiveRecord::Base 
    has_many :base_tags 
    has_many :primary_base_tags, conditions: {primary: true}, class_name: 'BaseTag' 
    has_many :tags, through: :base_tags 
    has_many :primary_tags, through: :primary_base_tags, class_name: 'Tag', source: :tag 
end 

模型然後ActiveRecord的正確設置主標誌我。

+0

謝謝,這就是我一直在尋找的東西。這個解決方案唯一的問題是,由於base_id和tag_id已經存在,推送已經在標籤列表中的primary_tag會給我一個RecordNotUnique錯誤。 – Tom

+1

如果某些東西既是主標籤又是標籤是合法的,那麼您必須更改索引以包含主列。 –

+0

這個實現有一個小問題。由於數據庫都是唯一的,所以在主要設置爲true和false的情況下,數據庫將不會有兩次保存相同的base_tag的問題。 – Tom

0

此解決方案可能適合您。我還添加了訪問primary_tags的替代版本,但由於您的版本可行,您可能不需要它。

class Base < ActiveRecord::Base 
    has_many :base_tags 
    has_many :tags, through: :base_tags 
    has_and_belongs_to_many :channels 

    def primary_tags 
    self.tags.includes(:base_tags).where(base_tags: { primary: true }) 
    end 

    def primary_tags_ids=(ids) 
    current_ids = self.base_tags.map(&:tag_id) 
    ids.each do |id| 
     if current_ids.include?(id) 
     self.base_tags.select { |bt| bt.tag_id == id }.first.primary = true 
     else 
     self.base_tags.build({ tag_id: id, primary: true }) 
     end 
    end 
    end 
end 
相關問題