Hey folks,
I have a few before filters which I am using to control access to resources on a resource-by-resource level. The basic idea is as follows:
- A user can be a
user
oradmin
and can have access to specific resources based on an "accesses" table. - Resources/methods can be limited in access to
admin
,owner
, particular users, or everyone.
This is best illustrated by some code examples. We have 4 application-level methods that are added to the call chain with before_filter
. Here is the top of an example controller class:
before_filter :require_user
before_filter :get_object, :only=>[:show, :edit, :update, :destroy]
before_filter :require_access, :only=>[:show]
before_filter :require_owner, :only=>[:edit, :update, :destroy]
As you can see, first we require that a user be logged in to access any method in this controller. Here are 3 fo the methods (defined in application.rb) so that you can see what they look like:
private
def get_object
begin
class_name = controller_name.gsub("Controller","").downcase.singularize
instance_variable_set "@#{class_name}".to_sym, class_name.capitalize.constantize.find(params[:id])
rescue
flash[:error] = "You do not have access to that #{class_name}."
redirect_to "/" and return
end
end
private
def require_owner
class_name = controller_name.gsub("Controller","").downcase.singularize
accessable = instance_variable_get("@#{class_name.downcase}")
unless accessable.user == current_user
flash[:error] = "You do not have access to that #{class_name.downcase}."
redirect_to "/" and return
end
end
private
def require_access
class_name = controller_name.gsub("Controller","").downcase.singularize
accessable = self.instance_variable_get("@#{class_name.downcase}")
unless current_user.has_access?(accessable)
flash[:error] = "You do not have access to that #{class_name.downcase}."
redirect_to "/" and return
end
end
This is all fine, as far as I can tell, from a coding perspective. But it's just so god-damn ugly! In particular the lines:
class_name = controller_name.gsub("Controller","").downcase.singularize
obj = instance_variable_get("@#{class_name.downcase}")
OR
instance_variable_set "@#{class_name}".to_sym, class_name.capitalize.constantize.find(params[:id])
Does anyone know of a bit more elegant way to do what I am doing here?