【问题标题】:Unable to return errors created on model无法返回在模型上创建的错误
【发布时间】:2013-10-28 17:39:40
【问题描述】:

我正在使用 gem Responders,但我无法显示我使用 erros.add(:base, 'Error message') 在我的模型上创建的错误。

在我的控制器上,在respond_with @app 之前,我调试了@app 对象,它 错误@app.errors.any? 返回true

在我看来,当我检查 flash@app 对象时,没有一个错误

应用控制器

# app_controllers.rb
def destroy
  @app = current_company.apps.find(params[:id])
  @app.destroy
  respond_with @app
end

应用模型

# app.rb

before_destroy :destroy_on_riak

# ...

def destroy_on_riak
  # SOME CODE HERE
rescue Exception => e
  errors.add(:base, I18n.t("models.app.could_not_destroy", :message => e.message))
  return false
end

应用视图

# apps.html.haml
-flash.each do |name, msg|
  %div{:class => "flash #{name}"}
    =content_tag :p, msg if msg.is_a?(String)

这是@app 对象之前 @app.destroy

"#<ActiveModel::Errors:0x00000004fa0510 @base=#<App id: 34, ...>, @messages={}>"

这是@app 对象之后 @app.destroy

"#<ActiveModel::Errors:0x00000004fa0510 @base=#<App id: 34, ...>, @messages={:base=>[\"Não foi possível excluir a aplicação: undefined method `get_or_new' for #<App:0x00000004f824c0>\"]}>"

为简单起见,我删除了 @base= 中的内容。

【问题讨论】:

    标签: ruby-on-rails ruby responders


    【解决方案1】:

    jefflunt 是正确的,当调用#valid? 时,它会清除错误数组:参见https://github.com/rails/rails/blob/4a19b3dea650351aa20d0cad64bf2d5608023a33/activemodel/lib/active_model/validations.rb#L333

    验证器旨在100% 确定对象的有效性,而不是在您自己添加错误以供以后使用时。

    虽然 ActiveRecord 确实覆盖了#valid?,但它仍然调用superhttps://github.com/rails/rails/blob/4a19b3dea650351aa20d0cad64bf2d5608023a33/activerecord/lib/active_record/validations.rb#L58

    如果您想添加错误并让它们持续存在,我建议您这样做:

    def failures
      @failures ||= []
    end
    
    validate :copy_failures_to_errors
    
    def copy_failures_to_errors
      @failures.each { |f| errors.add(*f) }
    end
    

    然后修改你的rescue:

    def destroy_on_riak
      # SOME CODE HERE
    rescue Exception => e
      failures.push([:base, I18n.t("models.app.could_not_destroy", :message => e.message)])
      return false
    end
    

    我知道这看起来令人费解,而且我知道网上甚至有一些示例供人们使用或推荐 errors.add(:base, ...),但它不是一种安全的方式来存储和检索错误以备后用。


    另外,只是一个建议,但我建议你拯救 StandardError 而不是 Exception,除非你绝对必须。内存不足错误和类似的东西是Exceptions,但是你想要拯救的每个正常错误都应该继承自StandardError。仅供参考。

    【讨论】:

      【解决方案2】:

      谜团似乎是(a)您可能没有调用正确的方法,或者(b).errors 哈希不包含您认为它包含的内容。

      方法不对?

      在您的控制器中,您调用@app.destroy,但添加错误的方法称为destroy_on_riak

      你确定你不是要输入这个吗?

      # app_controllers.rb
      def destroy
        @app = current_company.apps.find(params[:id])
        @app.destroy_on_riak    # <= The offending line?
        respond_with @app
      end
      

      或者您的代码示例中是否缺少before_destroy 回调,而该回调又调用destroy_on_riak?从包含的代码中,我看不到任何地方调用过 destroy_on_riak 方法,所以这只是一个猜测。

      .errors 哈希的意外内容?

      如果这不是问题所在,那么当@app.errors.any? 返回true 时,在代码中将@app.errors 的内容打印到您的日志中,以便您查看问题所在。

      【讨论】:

      • 感谢您的回答。正如您所想,destroy_on_riakbefore_destroy 上被调用(我已经用这个重要的细节更新了问题)。当我在 @app.destroy 之后放置 debugger 并且它在控制器和视图之间丢失时,@app.errors.any? 返回 true。
      • 如果您将debugger 行移到@app.destroy 调用之前,您可以在控制台中调用它并检查内容(并发布完整哈希的内容)。也许那里有线索。所以:@app.errors.inspect
      • 问题是用调试afterbefore更新的
      • 还有其他建议吗? :)
      【解决方案3】:

      我会给你一些提示:

      提示 1

      您的表单可能在 @app 对象上调用 valid?valid? 方法清除实例上的errors 数组。

      在验证上下文之外使用 errors 数组/构造是不正确的。但这是 MHO。

      提示 2

      根据 Responders gem(我过去从未使用过),您的语言环境只需要具有正确的配置。示例:

      flash:
        actions:
          create:
            notice: "{resource_name} was successfully created"
          update:
            notice: "{resource_name} was successfully updated"
          destroy:
            notice: "{resource_name} was successfully destroyed"
            alert: "{resource_name} could not be destroyed"
      

      是吗?

      【讨论】:

      • 感谢您的回答。关于语言环境,它是正确的。关于在验证上下文之外使用错误数组/构造是不正确的。,这样做的最佳方法是什么?
      【解决方案4】:

      我必须同意@p.mastinopoulos 的观点。这应该通过内置验证来处理。听起来您需要构建自定义验证器。

      http://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validate

      尝试用validate 替换您的before_destroy

      validate :destroy_on_riak, on: :destroy
      

      没有尝试过,但如果它不起作用,您可能需要考虑创建文档中引用的自定义验证器。

      【讨论】:

      • 感谢您的回答,我一定会尝试并报告。
      猜你喜欢
      • 2015-05-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-06
      • 1970-01-01
      • 2023-01-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多