Search code examples
ruby-on-rails-3routescontextpath

Rails 3 routing based on context


I am trying to implement a "context" system similar to the one used by GitHub. For example, a Post may be created belonging either to the User or one of the Companies the User belongs to depending on whether to User is in the "User" context or a context that refers to one of the Companies.

As a part of this, I'd like to be able to do routing based on the user's current context. For example, if the User is in their own context, /dashboard should route to users/show, but if they are in the context for Company with ID 35, then /dashboard should route to companies/35/dashboard.

I could route /dashboard to a special controller responsible for making such decisions, such as context#dashboard which could then do a redirect_to, but this doesn't feel quite right (perhaps because we're taking logic that the Rails routing module should be responsible for and moving it to a controller?)

What would be the proper way to solve this problem in Rails 3?


Solution

  • I finally found a solution to my problem that I like. This will use the URLs from my original question.

    First, assume a session-stored Context object that stores whether the user is in a "user" context or a "company" context. If the user is in a "company" context, then the ID of the company they're working as is in the object as well. We can get the context via a helper named get_context and we can get the currently logged-in user via current_user.

    Now, we set up our routes as so:

    config/routes.rb:

    MyApplication::Application.routes.draw do
      get "dashboard" => "redirect", :user => "/users/show", :company => "/companies/:id/dashboard"
    end
    

    Now, app/controllers/redirect_controller.rb:

    class RedirectController < ApplicationController
      def method_missing(method, *args)
        user_url    = params[:user]
        company_url = params[:company]
        context     = get_context
    
        case context.type
        when :user
          redirect_to user_url.gsub(":id", current_user.id.to_s)
        when :company
          redirect_to company_url.gsub(":id", context.id.to_s)
        end
      end
    end
    

    It's easy enough to keep the actual URLs for the redirect where they belong (in the routes.rb file!) and that data is passed in to a DRY controller. I can even pass in the ID of the current context object in the route.