如何处理此问题 - NoMethodError与NoRecordFound

时间:2011-02-16 12:04:37

标签: ruby-on-rails ruby ruby-on-rails-3

只是想知道处理以下问题的最佳方法,因为互联网上似乎存在相互矛盾的信息。我的代码开始像这样生活..

@merchant = Merchant.find_by_name(params[:merchant])
@products = @merchant.products.all.paginate(:page => params[:page])

现在效果很好,直到您点击商家不存在的网址,即/merchants/thisonedontexist/,此时我收到以下错误:

`undefined method `products' for nil:NilClass`

我理解为什么会收到此错误。

然后经过一些研究后,我决定用BANG(!)将我的代码更改为以下代码,这会引发NoRecordFound错误,因此它永远不会到达下一行,麻烦的是,我现在得到一个丑陋的错误:

@merchant = Merchant.find_by_name!(params[:merchant])
@products = @merchant.products.all.paginate(:page => params[:page])

错误是:ActiveRecord::RecordNotFound

经过一番研究后,我做了以下工作,并将这些请求重定向到404 ......

  def show
    @merchant = Merchant.find_by_name(params[:merchant])
    if !@merchant.nil?
      @products = @merchant.products.all.paginate(:page => params[:page])
    else
      redirect_to :status => 404
    end
  end

这似乎有效,但看起来非常笨重......这里的最佳做法是什么?

我希望它只显示一个类似"Sorry no category exists"的页面。

P.S。我是Rails的新手,也许这个问题有一个非常明显的答案

3 个答案:

答案 0 :(得分:2)

使用爆炸版是最好的方法。 NoMethodError让我觉得你没有正确处理应用程序工作流程。

此外,使用bang版本可以简化代码。 在生产中,ActiveRecord::RecordNotFound被拯救为404.这意味着,当错误被提出时,Rails将挽救错误并默认显示404错误页面,其中包含404状态代码。

请参阅source code

您可以简化代码

def show
  @merchant = Merchant.find_by_name!(params[:merchant])
  @products = @merchant.products.all.paginate(:page => params[:page])
end

答案 1 :(得分:0)

正如@simone所说,您可以将代码简化为

def show
  @merchant = Merchant.find_by_name!(params[:merchant])
  @products = @merchant.products.all.paginate(:page => params[:page])
end

现在,当找不到@merchant时,会引发异常。幸运的是,rails提供了一个很好的解决方案来很好地处理异常。

在您的控制器内(或ApplicationController,如果您想使其通用),您可以写

rescue_from ActiveRecord::RecordNotFound, :with => :handle_not_found

def handle_not_found
  # either 
  flash[:error] = ... some appropriate error message ...
  redirect_to :root # or some relevant path
end

因此,在该方法中,您可以根据需要执行任何想要处理异常的操作。

答案 2 :(得分:-1)

控制器

  def show
    @merchant = Merchant.find_by_name(params[:merchant])
    @products = @merchant.products.all.paginate(:page => params[:page]) if @merchant
  end

在您的视图/show.html.erb

if @merchant
  ...
  ...your code here
else
  <div>No such merchant</div>
end