多个关联到同一模型有很多通过

时间:2014-04-15 11:36:45

标签: ruby-on-rails activerecord

我目前有这些型号:

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会返回正确的记录,但在尝试创建/更新记录时:

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_ids创建与tag_ids相同的关联,当它应该真正更新关系时,主要属性应为1。

有没有办法让ActiveRecord玩得好听?我想我的has_many:primary_tags关系不正确。

2 个答案:

答案 0 :(得分: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为我正确设置主标志。

答案 1 :(得分: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
相关问题