我如何优雅地处理零例外?

时间:2014-09-18 23:37:17

标签: ruby-on-rails ruby-on-rails-4 exception-handling error-handling null

在我的/post/index.html视图中,我有这一行:

<%= post.status.upcase %>

每当post的状态值为nil时,我都会收到此错误:

NoMethodError at /
undefined method `upcase' for nil:NilClass

如何在我的应用程序中安全地处理所有nil值,这样就不会抛出这样的错误,只是优雅地降级甚至只是忽略它?

我是否必须遍历每个视图和每个可能具有可返回的属性的单个对象,并为每个对象添加异常处理?

是否有“Rails-y”DRY方式来处理这个问题?

4 个答案:

答案 0 :(得分:3)

忽略零是一个坏主意恕我直言。它将导致微妙的错误,无法追查。但是,如果你想要的例子是在status为零时输出一个空字符串(或根本没有),你有两个选择。对于我认为你正在做的事情,我更喜欢第一个,紧接着第二个,讨厌最后​​两个。

post.status.to_s.upcase

post.status.try(:upcase)

post.status.present? ? post.status.upcase : 'NO STATUS. OH NO'

begin
  post.status.upcase
rescue 
  'NO STATUS. OH NO'
end

答案 1 :(得分:2)

我只是想用另外一个选项来更新这个线程:Ruby now(从2.3开始)为我们提供了一个安全的导航操作符,&.语法。

所以:

post.status.upcase

会变成:

post.status&.upcase

与Rail的try方法类似,如果nil遇到NoMethodError,整个链将返回nil

答案 2 :(得分:0)

post如何定义?通常在控制器中,您可以设置一个实例变量,例如@post。我将假设帖子以某种方式从模型派生,在这种情况下,您真正​​想要做的是确保您永远不会将状态为nil的帖子保存到您的数据库中。您应该对Post模型进行验证,以确保始终存在状态,然后检查Post对象在创建时是否有效。所以像这样:

在您的模型中:

class Post < ActiveRecord::Base
validates :status, presence: true
...

然后在你的posts_controller.rb控制器中:

def create
...
if @post.save
  #handle successful save
else
  # handle unsuccessful save 
end

这样你就不会在数据库中找到错误的数据。

我想另一种(hacky)解决这个问题的方法是在你的模型中创建一个方法,以确保你永远不会从状态方法中得到一个null,所以像这样:

class Post
...
def status
  read_attibute(:status) || ""  # return an empty string is status is null - this is a hack, I should fix this at some point by making sure the a status of nil is never saved to the database!
end

或根据您在上述答案中的评论,您总是可以将补丁活动记录设为永不返回nil,而是为每个类返回一些默认值。

文件activerecord / lib / active_record / base.rb,第1870行

  def read_attribute(attr_name)
    attr_name = attr_name.to_s
    if !(value = @attributes[attr_name]).nil?
      if column = column_for_attribute(attr_name)
        if unserializable_attribute?(attr_name, column)
          unserialize_attribute(attr_name)
        else
          column.type_cast(value)
        end
      else
        value
      end
    else
      nil # return whatever you think is appropriate 
    end
  end

答案 3 :(得分:0)

将它放在Application_controller.rb

rescue_from Exception::NoMethodError, :with => :render_error

private
def render_error
render :file => "#{Rails.root}/public/methodnotfound.html", :status => 404, :layout => false
end

并使用消息&#34; methodnotfound.html&#34;创建html。