Forum: Ruby on Rails Routes.recognize_path on more complicated Routes

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
13cc2e8b66281880937d4e8eed4cbf77?d=identicon&s=25 Danny Tipple (dannytip)
on 2009-03-06 15:56
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
E6dd88ec54643689069f97f0d52398ca?d=identicon&s=25 Jakub Tesinsky (gorn)
on 2009-03-16 03:47
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
13cc2e8b66281880937d4e8eed4cbf77?d=identicon&s=25 Danny Tipple (dannytip)
on 2009-03-16 10:25
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]
This topic is locked and can not be replied to.