For a permissions system i’m writing i’m extending the standard link_to
helpers to check if a user has a permission to perform that action
before displaying a link to clean-up my code so i don’t have to put if
checks all over them.
I’m trying to use…
ActionController::Routing::Routes.recognize_path(url, :method => method)
to get the action and controller out so i can check those permissions.
The problem im having is when it comes to more complicated routes the
recognize_path method gets things mixed up e.g.
/admin/users/60/edit - Controller: admin/users | Action: 60 | Id: edit -
Correct
/admin/users/60 - Controller: admin/users | Action: destroy | Id: 60 -
Correct
/admin/users/60/ban - Controller: admin/users | Action: 60 | Id: ban -
Incorrect
As you see the ban link has the action and id the wrong way round.
Is there a correct way around this rather than just swapping the 2
values round?
Also when doing a nested route like…
ActionController::Routing::Routes.recognize_path("/admin/chat_rooms/15/quick_chats/new")
It errors saying “Only get, put, and delete requests are allowed.” even
though that route works perfectly fine in a view.
The projects currently running on rails 2.0.1 if that helps.
Danny
Hi Danny,
good to see that someone is trying to achieve EXACTLY the same thing
like me. I have even tried to dig deep in the link_to implementation to
solve this, but it is more than black magic and I soon gave up. Do you
have any new ideas regarding the problem?
Jakub
Hi Jakub
Here’s the implementation i ended up with. Its not very clean but it
does the job.
[code] def link_to(*args, &block)
unless params[:controller] =~ /admin/
super
else
if args.size > 2
super if action_allowed(args[1], args[2][“method”])
else
super if action_allowed(args[1])
end
end
end
def link_to_remote(name, options = {}, html_options = nil)
unless params[:controller] =~ /admin/
super
else
super if action_allowed(options[:url], options[:method])
end
end
def action_allowed(url, method = :get)
return false unless current_user
path = ActionController::Routing::Routes.recognize_path(url, :method
=> method) rescue nil
return true unless path
return true if current_user.roles.find(:first, :conditions =>
[“unrestricted = ?”, true])
permissions = Permission.find(:all, :conditions => ["role_id in
(?)", current_user.roles.map(&:id)])
if path[:action] =~ /^\d+$/
perm = permissions.select { |p| p.controller == path[:controller]
&& p.action == path[:id] }.first
else
perm = permissions.select { |p| p.controller == path[:controller]
&& p.action == path[:action] }.first
end
return true if perm
false
end[/code]