如果has_many,通过:关联,如何验证相关记录的存在?

时间:2016-07-27 14:49:29

标签: ruby-on-rails validation activerecord has-many-through has-many

有些模型具有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:在回答之前,请仔细阅读粗体中标记的句子。 Rails 4.2.1

3 个答案:

答案 0 :(得分:2)

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

cars.com/search;year=2010;model=true;brand=Mazda

这显示了一般的想法,您可以根据自己的需要进行调整。

<强>更新

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

验证可以保持如上。我必须添加的是直接分配一组空类别的情况。那么,我该怎么做?

这个想法很简单:覆盖setter方法不接受空数组:

validate :has_categories

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

这将适用于每个作业,除非指定空集。然后,根本不会发生任何事情。不会记录任何错误,也不会执行任何操作。

如果您还想添加错误消息,则必须即兴发挥。将一个属性添加到将在铃声响起时填充的类中。 所以,简而言之,这个模型对我有用:

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

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

答案 1 :(得分:0)

使用validates_associated,官方文档为Here

答案 2 :(得分:-2)

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

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