Using Filters to Authenticate
false
, the action is never called. You can use the the logged_in?
method of :acts_as_authenticated
to prohibit access to non-users — just add before_filter :logged_in?
to your controller class and you're set!Using Filters to Load Data
Today I refactored all my controllers to depend on a
before_filter
to load their objects. Beforehand, each action followed a predictable pattern:- Read an ID from the parameters
- Load the object for that ID from the database
- If that object was the child of an object I also needed, load the parent object as well
To eliminate this, I added a very simple method to my
ApplicationController
class:def load_objects_from_params
if params[:work_id]
@work = Work.find(params[:work_id])
end
if params[:page_id]
@page = Page.find(params[:page_id])
@work = @page.work
end
end
I then added before_filter :load_objects_from_params
to the class definition and removed all the places in my subclasses where I was calling find
on either params[:work_id]
or params[:page_id]
.The result was an overall 7% reduction in lines of code -- redundant, error-prone lines of code, at that!
Line counts before the refactoring:
7 app/controllers/application.rbAnd after:
19 app/controllers/dashboard_controller.rb
10 app/controllers/display_controller.rb
138 app/controllers/page_controller.rb
87 app/controllers/transcribe_controller.rb
47 app/controllers/work_controller.rb
[...]
1006 total
28 app/controllers/application.rbIn the case of my (rather bare-bones)
19 app/controllers/dashboard_controller.rb
2 app/controllers/display_controller.rb
108 app/controllers/page_controller.rb
69 app/controllers/transcribe_controller.rb
34 app/controllers/work_controller.rb
[...]
937 total
DisplayController
, the entire contents of the class has been eliminated!Perhaps best of all is the effect this has on my authentication code. Since I track object-level permissions, I have to read the object the user is acting upon, check whether or not they're the owner, then decide whether to reject the attempt. When the objects may be of different types in the same controller, this can get a bit hairy:
if ['new', 'create'].include? action_name
# test if the work is owned by the current user
work = Work.find(params[:work_id])
return work.owner == current_user
else
# is the page owned by the current user
page = Page.find(params[:page_id])
return page.work.owner == current_user
After refactoring my ApplicationController
to call my load_objects_from_params
method, this becomes:return @work.owner == current_user
1 comment:
According to the api (see URL below), the filters do not need to return a boolean. It is enough that they redirect or render. Quoting: "If before renders or redirects, the second half of around and will still run but after and the action will not."
http://api.rubyonrails.org/classes/ActionController/Filters/ClassMethods.html
Post a Comment