如何在before_filter中处理无效ID?

时间:2011-06-06 15:51:30

标签: ruby-on-rails controllers

假设我的控制器看起来像这样:

class MyController < ApplicationController
  before_filter :find_user,:only => [:index,:create,:update,:destroy]
  def index
     @some_objects = @user.objects.all
  end

  ...

  private
  def find_user
    @user = User.find(params[:user_id])
  end

end

如果user_id param不存在,@ user将为nil。我认为这不是这样的:

def index
   if @user
      @some_objects = @user.objects.all
   else
      # ?
   end
end

在我的控制器中进行所有这些检查代码看起来更加丑陋...更不用说如果其他控制器与此类似,我必须复制很多逻辑。 你如何处理这些案件?

4 个答案:

答案 0 :(得分:2)

如果user_id参数不存在,则find方法抛出ActiveRecord::RecordNotFound异常。此异常捕获在before_filter和呈现的错误中。 Аll后续过滤器和index操作将不会被调用。

class MyController < ApplicationController
  before_filter :find_user,:only => [:index,:create,:update,:destroy]
  def index
     @some_objects = @user.objects.all
  end

  private
  def find_user
    @user = User.find(params[:user_id])
  rescue ActiveRecord::RecordNotFound
    # render or redirect_to error
  end

end

答案 1 :(得分:1)

我认为它应该放在同一个过滤器中:

private
def find_user
  @user = User.find_by_id(params[:user_id])
  redirect_to where_you_want_to_go_when_no_user_url unless @user #for example login page
end

如果你想在没有@user的情况下呈现你的控制器动作而你总是需要@some_objects(并且你不希望变量为null),你可以有另一个before_filter:

def get_some_objects
  @some_objects = @user.present? ? @user.objects.all : []
end

或组合两个选项(重定向或设置some_objects变量):

def set_variables
  @user = User.find_by_id(params[:user_id])
  if @user
    @some_objects = @user.objects.all
  else
    redirect_to where_you_want_to_go_when_no_user_url
  end
end

我希望这会有所帮助。

编辑:当id为null或者给定id的用户不存在时,将'find'更改为'find_by_id'以避免错误。

答案 2 :(得分:1)

使其完全干燥的最佳方法是使用专用宝石:inherited_resources

它基本上会为您处理一切,根据上下文按预期预加载资源。

当然,您可以添加所需的特定范围,请参阅教程。

答案 3 :(得分:0)

当您要求特定ID并且AR无法找到它时,它会抛出RecordNotFound错误。 你必须抓住这样的东西:

irb(main):025:0> begin
irb(main):026:1* Location.find 100
irb(main):027:1> rescue ActiveRecord::RecordNotFound => e
irb(main):028:1> puts "Oops: #{e.message}"
irb(main):029:1> end
Oops: Couldn't find Location with ID=100
=> nil

如果您想对所有控制器应用某些内容,您应该考虑将您的方法添加到ApplicationController ......