Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to specify two root pages in Rails (one for anonymous user another for logged in user)

I am building a product that has static pages and dynamic pages(product related). Both category of pages have different release life cycle. The marketing team working with the designer, release the static pages and the product pages are released by the engineering team.

The static pages reside in public/home and they are self contained. They don't need access to the Rails infrastructure other than providing links.

In this setup, I am trying to implement the following behavior:

  • When an un-authenticated visitor launches http://www.xyz.com, the user should be taken to the static landing page.

  • When an authenticated visitor launches http://www.xyz.com, the user should be taken to the product landing page (LandingsController, index action).

In my current implementation, I check if the user is authenticated in the Rails world and render the static page OR the product page.

I want to know the following:

1) How do you handle such scenarios?

2) Is there a way to avoid entering the Rails stack for static home page.

3) Is there a customization for the root_path method to return different root based on the context

like image 213
Harish Shetty Avatar asked Sep 08 '10 03:09

Harish Shetty


2 Answers

1) How do you handle such scenarios?

The common answer would look like this:

class LandingsController < ApplicationController

  before_filter :login_required

  def index
    ...
  end

  ...

  private

    def login_required
      if not_logged_in? # This methods depends on your authentication strategy
        send_file "/your/static/path/#{params[:action]}", :type => "application/html charset=utf8;"
        return false # Halt chain
      end
    end

send_file documentation

And, depending on the correspondence between each of your actions and your templates, you can further abstract the login_required method into the ApplicationController, and validate if the file exists.

2) Is there a way to avoid entering the Rails stack for static pages

Yes. You have to take my word for it, because I haven't done it myself, but you can use a Rack middleware to do that. Here is an example of how to do something similar, with the exception that instead of a redirect, you would serve the file statically (just set the headers and the results of File.read as content) This depends on the authentication library you're working with, though.

3) Is there a customization for the root_path method to return different root based on the context

You cannot define a conditional route (that is, defining multiple routes in the routes.rb file), but you can override the root_url method in ApplicationController, assuming you are using a named path root in your route definitions. Something like

class ApplicationController

  def root_url(*options)
    if logged_in?
      "/return/something/custom"
    else
      super(*options)
    end
  end

end

This, however, sound really a bad idea, since 1) You should point to the same url, and let the controller handle the request (your links should be blind of where to take you), and 2) It may potentially break other stuff that rely on the root_url and root_path methods.

like image 67
Chubas Avatar answered Oct 07 '22 23:10

Chubas


Unfortunately, Rails' routing can only route requests to different controllers based on something in the request, making the per-request session data just out of reach. Your current implementation is certainly the most common strategy. I am guessing something like this:

def index
  if logged_in?
     # any logged in logic you need.
  else
     render :file => 'public/home', :layout => false
  end
end

The only way to refactor this to make it feel less "icky" is to move that render call to a before_filter. Since the filter will have rendered?, your action won't get invoked at all. Of course, you could also choose to redirect_to another location for authenticated (or non-authenticated) requests in a before filter, which would solve the problem entirely.

The only thing you could do would be based on the non-existence of the session cookie.

  1. Write a middleware component or Rack application (etc.) that explicitly handles the request if no session cookie is present. Similarly, you could use middleware to re-write the request, and then pass it onto the application layer.
  2. Use a similar strategy as #1, but do it via web server configuration (Apache or nginx), avoiding the Rails app entirely.

But, it's definitely possible for someone to have a session and yet not be logged in (e.g. if they went to another page which you didn't handle this way), or even have invalid session data, so you wouldn't be able to actually eliminate the code you have now. These changes would only serve to increase the performance of the session-less requests, but unless those pages are causing a significant problem (which I doubt), so I would not recommend doing so.

like image 31
wuputah Avatar answered Oct 07 '22 22:10

wuputah