Let's say my controller looks like this:
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
If the user_id
param does not exist, @user will be nil.I think this is not the way:
def index
if @user
@some_objects = @user.objects.all
else
# ?
end
end
The code would look uglier having all these checks in my controller ... not to mention I'd have to duplica开发者_运维问答te a lot of the logic if other controllers are similar to this one. How do you deal with these cases?
If the user_id
param does not exist, then find
method throw ActiveRecord::RecordNotFound
exception. This exception is caught in a before_filter and rendered error. Аll subsequent filters and the index
action will not be called.
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
The best way to make it perfectly dry is to use a dedicated gem: inherited_resources
It will basically handle everything for you, preloading as expected your resources according to the context.
Of course you can add your desired specific scopes, see tutorial.
I think it should be placed in the same filter:
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
If you want to render your controller actions even without a @user and you always need the @some_objects (and you don't want the variable to be null), you can have another before_filter:
def get_some_objects
@some_objects = @user.present? ? @user.objects.all : []
end
or combining both options (redirect or set some_objects variable):
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
I hope this helps.
EDIT: change 'find' to 'find_by_id' to avoid errors, when id is null or user for given id does not exist.
When you ask for a specific id and AR can't find it, it throws a RecordNotFound error. You would have to catch that with something like:
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
If you are wanting to apply something to all controllers you should probably think about adding your method to ApplicationController...
精彩评论