ruby on rails-如何在has_many的情况下验证关联记录的存在,通过:association



有一些型号具有has_many through关联:

class Event < ActiveRecord::Base
  has_many :event_categories
  has_many :categories, through: :event_categories
  validates :categories, presence: true
end
class EventCategory < ActiveRecord::Base
  belongs_to :event
  belongs_to :category
  validates_presence_of :event, :category
end
class Category < ActiveRecord::Base
   has_many :event_categories
   has_many :events, through: :event_categories
end

问题在于分配event.categories = []-它会立即从event_categories中删除行因此,以前的关联将被不可逆转地破坏,事件将失效。

has_many, through:的情况下,如何验证记录的存在?

UPD:在回答之前,请仔细阅读粗体标记的句子。轨道4.2.1

您必须创建一个自定义验证,如下所示:

validate :has_categories
def has_categories
  unless categories.size > 0
    errors.add(:base, "There are no categories")
  end
end

这向你展示了总体思路,你可以根据自己的需求进行调整。

更新

这篇文章又出现了,我找到了填补空白的方法。

验证可以保持如上所述。除此之外,我要补充的是直接分配一组空类别的情况。那么,我该怎么做呢?

想法很简单:重写setter方法以不接受空数组:

def categories=(value)
  if value.empty?
    puts "Categories cannot be blank"
  else
    super(value)
  end
end

这将适用于每个赋值,除非赋值为空集。然后,什么都不会发生。不会记录任何错误,也不会执行任何操作。

如果你还想添加一条错误消息,你必须即兴发挥。为类添加一个属性,该属性将在铃声响起时填充。所以,长话短说,这个模型对我有效:

class Event < ActiveRecord::Base
  has_many :event_categories
  has_many :categories, through: :event_categories
  attr_accessor :categories_validator # The bell
  validates :categories, presence: true
  validate  :check_for_categories_validator # Has the bell rung?
  def categories=(value)
    if value.empty?
      self.categories_validator = true # Ring that bell!!!
    else
      super(value) # No bell, just do what you have to do
    end
  end
  private
  def check_for_categories_validator
    self.errors.add(:categories, "can't be blank") if self.categories_validator == true
  end
end

在添加了最后一次验证后,如果您这样做,实例将无效:

event.categories = []

但是,不会执行任何操作(跳过更新)。

使用validates_associated,官方文档在这里

如果您使用RSpec作为测试框架,请查看Shoulda Matcher。这里有一个例子:

describe Event do
  it { should have_many(:categories).through(:event_categories) }
end

最新更新