2011-06-06 44 views
3

比方说,我的控制器看起来像这样:如何处理before_filter中的无效ID?

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参数不存在,@user将nil.I认为这是没有办法的办法:

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

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

回答

2

如果user_id PARAM做不存在,则find方法抛出ActiveRecord::RecordNotFound异常。这个异常在before_filter和呈现的错误中被捕获。所有后续过滤器和index操作都不会被调用。

​​
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(和你不想要的变量为空),你可以有另一种的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'为空或给定id的用户不存在时,将'find'更改为'find_by_id'以避免错误。

1

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

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

当然你可以添加你想要的特定范围,参见教程。

+0

我不知道这个宝石。谢谢(你的)信息。 – santuxus 2011-06-07 07:43:39

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中所有控制器...

+0

您可以随时使用'find_by_id'而不是'find' - 当找不到记录时它返回nil。 – santuxus 2011-06-06 16:31:45

+0

聪明!我没有想到这一点。谢谢! – mikewilliamson 2011-06-06 16:50:45

+0

不客气! – santuxus 2011-06-07 07:43:53