在销毁之前验证

tan*_*man 52 validation ruby-on-rails

我有三个类:School,Account,和Administratorship.

学校

has_many :administatorships
has_many :administrators, :through => :administratorships
Run Code Online (Sandbox Code Playgroud)

帐户

has_many :administratorships
Run Code Online (Sandbox Code Playgroud)

管理人的职位

belongs_to :account
belongs_to :school

before_destroy :confirm_presence_of_alternate_administratorship_in_school

protected

def confirm_presence_of_alternate_administratorship_in_school
    unless school.administrators.count(["administratorships.account_id != #{id}"]) > 0
        errors.add_to_base "The school must have at least one administrator"
    end
end
Run Code Online (Sandbox Code Playgroud)

现在,我想要发生的是当我调用destroy一个实例时Administratorship,它会向模型添加错误并防止模型的破坏.我已删除该unless语句以查看是否阻止添加错误,但事实并非如此.似乎模型上有错误并不能防止破坏发生.

所以我的问题是,有什么方法可以防止使用验证发生破坏?我意识到我可以定义一个仅在满足上述条件时才会销毁的方法,但似乎验证方法是一种更优雅的解决方案.

小智 67

如果从before_destroy方法返回false,则会阻止销毁.

  • 如果有人偶然发现在寻找Rails 5,那么返回false就不再那样了.使用`throw(:abort)`,就像在Martin Cabrera Diaubalick的回答中一样. (6认同)
  • 对于在销毁之前希望对象处于有效状态的一般情况,你可以这样做:`before_destroy:valid? (3认同)

小智 33

这是一个Rails 5的答案,如果你返回false,它会给出一个弃用警告:"返回falseActive Record和Active Model回调不会隐式停止Rails 5.1中的回调链".

def confirm_presence_of_alternate_administratorship_in_school
  return if school.administrators.count(["administratorships.account_id != #{id}"]) > 0
  errors[:base] << 'The school must have at least one administrator'
  throw :abort
end
Run Code Online (Sandbox Code Playgroud)


Rya*_*yan 15

false从验证方法返回将阻止记录被销毁.

例:

def confirm_presence_of_alternate_administratorship_in_school
  unless school.administrators.count(["administratorships.account_id != #{id}"]) > 0
    # errors.add_to_base() is deprecated in Rails 3. Instead do...
    errors.add(:base, "The school must have at least one administrator")

    # this will prevent the object from getting destroyed
    return false
  end
end
Run Code Online (Sandbox Code Playgroud)

附注:我无法显示此错误消息.验证将起作用,对象不会被删除,但没有消息让我知道发生了什么.原因是控制器重定向到索引视图而不是渲染删除视图(例如,如果在创建新用户时出现错误,它将呈现:action =>'new'.在这种情况下,有没有删除视图).发生这种情况时,实际上正在重置设置了错误消息的实例变量(在errors.add(:base,"message")中),这会破坏进程中的错误.

  • 要解决**侧注**中出现的问题,请在相关控制器的destroy动作中的`redirect_to`行添加如下内容:`format.html {redirect_to products_url,:notice =>"An Error发生了!#{@ products.errors [:base] .to_s}"}`.然后只要你在应用程序的某个地方显示flash消息(例如application.html.erb),它就会出现.请参阅[本指南](http://guides.rubyonrails.org/action_controller_overview.html#the-flash)和[此问题](http://stackoverflow.com/q/9390778/664833). (5认同)
  • 有没有办法解决你在旁注上提出的问题? (2认同)