Routes.recognize_path on more complicated Routes

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]