2

有型号,有has_many through协会:如何在has_many的情况下通过关联来验证关联记录的存在?

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

回答

0

使用validates_associated,官方文件建立是Here

+0

从docs - '验证关联的对象或对象是否全部有效'和'如果关联尚未分配,此验证将不会失败。如果您想确保该关联既存在也可以保证有效,则还需要使用validates_presence_of。'。但是,即使将“validates_presence_of:categories”和“validates_associated:categories”组合在一起,也不会阻止在分配“event”时从“event_categories”表中立即删除。分类= []' – yurko

-1

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

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

我不问如何测试它,但如何验证它 – yurko

1

你必须创建一个自定义的验证,如:

validate :has_categories 

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

这说明你的总体思路,可以适应这个您的需求。

UPDATE

本帖上来一次,我找到了一种方法来填补空白。

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

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

def categories=(value) 
    if value==[] 
     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==[] 
      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 = [] 

虽然没有动作会已经完成(更新被跳过)。

+0

它不会阻止在分配'event.categories = []时立即从'event_categories'表中删除' – yurko

+0

如果您尝试'event_categories .size'代替;? –

+0

立即从'event_categories'删除 – yurko

相关问题