Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic Rails routing based on database

I'm building a CMS with various modules (blog, calendar, etc.) using Rails 2.3. Each module is handled by a different controller and that works just fine.

The only problem I have is with the root URL. Depending on the configuration chosen by the user, this default URL should show a different module i.e. a different controller, but the only way I have to determine the correct controller is by checking the database for what "default" module is to be shown.

For the moment I'm using a specific "root" controller which checks the database and redirects to the correct controller. However I'd prefer the URL not to be changed, which means I want to invoke the correct controller from the very same request.

I've tried using Rails Metal to fetch this info and manually calling the controller I want but I'm thinking I may be reinventing the wheel (identify the request path to choose the controller, manage session, etc.).

Any idea? Thanks a lot in advance!

like image 657
Nicolas Jacobeus Avatar asked Oct 05 '09 08:10

Nicolas Jacobeus


People also ask

How many types of routes are there in Rails?

Rails RESTful Design which creates seven routes all mapping to the user controller. Rails also allows you to define multiple resources in one line.

What is rake routes?

rake routes will list all of your defined routes, which is useful for tracking down routing problems in your app, or giving you a good overview of the URLs in an app you're trying to get familiar with.

How do Rails routes work?

Rails routing is a two-way piece of machinery – rather as if you could turn trees into paper, and then turn paper back into trees. Specifically, it both connects incoming HTTP requests to the code in your application's controllers, and helps you generate URLs without having to hard-code them as strings.

What is the difference between resources and resource in Rails?

Difference between singular resource and resources in Rails routes. So far, we have been using resources to declare a resource. Rails also lets us declare a singular version of it using resource. Rails recommends us to use singular resource when we do not have an identifier.


2 Answers

This problem can be solved with some Rack middleware:

This code in lib/root_rewriter.rb:

module DefV
  class RootRewriter
    def initialize(app)
      @app = app
    end

    def call(env)
      if env['REQUEST_URI'] == '/' # Root is requested!
        env['REQUEST_URI'] = Page.find_by_root(true).uri # for example /blog/
      end

      @app.call(env)
    end
  end
end

Then in your config/environment.rb at the bottom

require 'root_rewriter'
ActionController::Dispatcher.middleware.insert_after ActiveRecord::QueryCache, DefV::RootRewriter

This middleware will check if the requested page (REQUEST_URI) is '/' and then do a lookup for the actual path (Implementation to this is up to you ;-)). You might do good on caching this info somewhere (Cache.fetch('root_path') { Page.find... })

There are some problems with checking REQUEST_URI, since not all webservers pass this correctly. For the whole implementation detail in Rails see http://api.rubyonrails.org/classes/ActionController/Request.html#M000720 (Click "View source")

like image 160
Jan De Poorter Avatar answered Oct 16 '22 05:10

Jan De Poorter


In Rails 3.2 this was what I came up with (still a middleware):

class RootRewriter
  def initialize(app)
    @app = app
  end

  def call(env)
    if ['', '/'].include? env['PATH_INFO']
      default_thing = # Do your model lookup here to determine your default item
      env['PATH_INFO'] = # Assemble your new 'internal' path here (a string)
      # I found useful methods to be: ActiveModel::Naming.route_key() and to_param
    end

    @app.call(env)
  end
end

This tells Rails that the path is different from what was requested (the root path) so references to link_to_unless_current and the like still work well.

Load the middleware in like so in an initialiser:

MyApp::Application.config.middleware.use RootRewriter
like image 43
Brendon Muir Avatar answered Oct 16 '22 04:10

Brendon Muir