Rails 5 throw abort:如何设置错误消息?

Cyr*_*ris 8 activemodel ruby-on-rails-5

Rails已经引入了这种throw(:abort)语法,但现在我如何获得有意义的销毁错误?

对于验证错误,人们会这样做

if not user.save
  # => user.errors has information

if not user.destroy
  # => user.errors is empty
Run Code Online (Sandbox Code Playgroud)

这是我的模特

class User

  before_destroy :destroy_validation,
    if: :some_reason

  private

  def destroy_validation
    throw(:abort) if some_condition
  end
Run Code Online (Sandbox Code Playgroud)

小智 17

您可以使用errors.add您的类方法.

用户模型:

def destroy_validation
  if some_condition
    errors.add(:base, "can't be destroyed cause x,y or z")
    throw(:abort)
  end
end
Run Code Online (Sandbox Code Playgroud)

用户控制器:

def destroy
  if @user.destroy
    respond_to do |format|
      format.html { redirect_to users_path, notice: ':)' }
      format.json { head :no_content }
    end
  else
    respond_to do |format|
      format.html { redirect_to users_path, alert: ":( #{@user.errors[:base]}"}
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

  • 从“has_many”集合中销毁元素时并不完全正确, - 不会创建错误消息:“post.comments.destroy(comment)”不会引发任何错误(至少在 Rails 控制台中),但“comment”元素会在这种情况下不会被破坏。假设您有一个具有“has_many”注释关系的“Post”模型,并且在声明“has_many”关系之前在 Post 模型中定义了“before_destroy”回调。 (3认同)

3li*_*t0r 6

贡萨洛·S 的回答非常好。但是,要清理 coede,您可以考虑使用辅助方法。以下代码在 Rails 5.0 或更高版本中效果最佳,因为您可以使用该ApplicationRecord模型。

class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true

  private

  def halt(tag: :abort, attr: :base, msg: nil)
    errors.add(attr, msg) if msg
    throw(tag)
  end

end
Run Code Online (Sandbox Code Playgroud)

现在你可以这样做:

class User < ApplicationRecord

  before_destroy(if: :some_reason) { halt msg: 'Your message.' }

  # or if you have some longer condition:
  before_destroy if: -> { condition1 && condition2 && condition3 } do
    halt msg: 'Your message.'
  end

  # or more in lines with your example:
  before_destroy :destroy_validation, if: :some_reason
  
  private

  def destroy_validation
    halt msg: 'Your message.' if some_condition
  end

end
Run Code Online (Sandbox Code Playgroud)