If you're new here, you may want to subscribe to my RSS feed. So that you can read the latest updates about Web2.0 tools, Making Money Online, Tips in SEO, Ajax and many more. Thanks for visiting ProgramimiCOM!

In an MVC based web application, it is the controller that orchestrates and controls the flow of application logic. So to create an efficient, scalable and robust application, the clear understanding of the controller component provided by the framework is necessary. RoR is no exception.The Controller component provided by RoR is the ActionController. In this discussion I will focus on the ActionController. The first sections will cover the services provided by ActionController and the techniques to access them. The final section will provide insight into using these techniques in the real world.  So let’s get started.

Into the World of the ActionController

In RoR, the Action Pack forms the core of the framework. It contains two modules, the ActionView and the ActionController. One aspect of the Action Pack is that it cannot be used as a part of anything but a web application. With this in mind let’s look at what happens when a URL such as http://localhost:3000/demo/say/hello is called. As discussed in the previous article, a URL consists of the application name, then the controller name and finally the action name. So what RoR really does when a URL is typed in can be divided into the following steps :

  1. It loads the file say_controller.rb situated in the app/controllers directory. It happens only once in a production environment.
  2. Then RoR instantiates an object of the class named SayController.
  3. Once the class has been instantiated, it looks into app/helpers for a file named say_helper.rb. If it exists, it is loaded and the module SayHelper is mixed into the SayController object. That means the methods of the SayHelper module will be available directly from within the instantiated object of SayController.
  4. It then loads the model from say.rb within the app/models if found.

Now that the sequence of application initialization is cleared, let’s move on to the services provided by the ActionController. The usage of the services will be discussed in detail in the future. The Controller component of the RoR provides the following services:

  1. Routing the requests
  2. Session tracking
  3. Filtering and Verification
  4. Caching

The next obvious question would be “why are all these services provided by the Controller component?” The answer lies with the fact that in an MVC based architecture, the Controller sits at the boundary of the application. Hence it can monitor every kind of data flow within the application and redirect or reroute if required. Many of these “flows” require the tracking of the details of the current user, caching the generated data for performance enhancements, and so on. So the best component to provide these services is the Controller. With that, here are the details.

Routing the Requests, and Session Tracking

1. Routing the requests

If you tried out the application developed in last part, you would remember a URL of the form of http://localhost:3001/admin/show/1/. The question that arises is, how does RoR map such a URL to a specific method or class? The mapping is done by routing the information contained in a file named routers.rb within the config directory. The information would look like the following code:

ActionController::Routing::Routes.drawdo|map|
map.connect ‘:controller/service.wsdl‘, :action => ‘wsdl
map.connect ‘:controller/:action/:id
end

The Routing component of the ActionController creates a map that connects the external URLs to the internals of the application. To make it more clear, look at the third line of the code block. The second map.connect statement contains the string :controller/:action/:id‘. It acts as a pattern to be matched against the path portion of the request URL. In the case of the request URL, the path can again be subdivided into three parts:

a. The first part would be assigned to the :controller part of the pattern.

b. The second part would be assigned to the :action part of the pattern.

c. The third part would be assigned to the :id part of the pattern.

On the basis of the above deduction, http://localhost:3001/demo/admin/1/ would be mapped as:

@params = { :controller => ‘admin’,
:action => ‘show‘,
:id => 1 }

Based on this, RoR would invoke the show method in the admin controller with a parameter for the id of 1. Thus with this simple yet powerful technique, RoR does many things.

2. Session Tracking

Tracking a user across the application is the most required capability for any web application. Tracking can be done, in an efficient way, either by using cookies or session management provided by the framework. RoR provides both of these implicitly without the requirement of using explicit objects by means of the ActionController. Look at the following code block:

  class CookiesController < ApplicationController
def create_cookie
cookies[:the_time] = Time.now.to_s
redirect_to :action =>
“action_two”
end

    def get_cookie
cookie_value = cookies[:the_time]
render(:text =>“The cookie says it is #{cookie_value}”)
    end
  end

In the code above, there are two action methods in the Controller, one that sets a cookie and another that reads the cookie and displays the value. Here cookies[] is an implicit array/list of cookie objects. A new cookie can be added by specifying the name and providing the value.

Next the :action (which is a parameter of redirect_to) is given to the controller to which the request has to be redirected. In this case it is get_cookie action. In the second action the value of the cookie is extracted and shown using the render() method.

That covers cookies. But it is much better if there is a method to implement cookies transparently. That technique is the use of session. Just like cookies, session is also implicit. Its syntax and usage is similar to that of the cookie object. The following code will make it more clear:

  class SessionController < ApplicationController
    def login
user = User.find_by_name_and_password(params[:user], params[:password])
if user
session[:user_id] = user.id
redirect_to :action =>
“index”
else
reset_session
flash[:note] =
“Invalid user name/password”
    end
end

The above code checks the user-id and password. If the user is valid it sets the user-id in session. The statement session[:user_id] = user.id. is the same as setting a cookie. Next the user is redirected to the index page. If the user is not valid, the session is invalidated using reset_session. This again reflects the simplicity of RoR.

Filtering and Verification, and Caching 

3. Filtering and Verification

There are situations where certain processing must be done before a request is serviced. In such situations filters come into the picture. Filters are pieces of code that wrap the logic that needs to be called before or after any number of actions within the controller or its derived classes. There are two kinds of filters, before and after filters. The before filters work before a request has been processed, whereas the after filters do the task after the action has been invoked. For example, if a code for verifying a user’s session must be called before invoking an action, the code would be:

  def authorize
unless session[:user_id]
flash[:notice] =“Please log in”
redirect_to(:controller =>“login”, :action =>“login”)
end
end

  class AdminController < ApplicationController
before_filter :authorize
# …

Here the code to be executed before invoking any action within the AdminController is wrapped inside the authorize function, which is then called before any other action using the before_filter. The after_filter also works in the same way.

Filters can only call a code to be executed, but in situations where the need is to verify that a certain condition is met before an action is executed, filters can’t do much. It is here that verification comes handy. Verification can be done by using the verify. Let’s visualize a situation where the conditions are: the user-id must be valid, the user can only post comments, and if the conditions are met, redirect to the index page. The code using verify would be:

  class BlogController < ApplicationController
verify :only => :post_comment,
:session => :user_id,
:add_flash => { :note =>“You must log in to comment”},
:redirect_to => :index

  # …

Its that easy.

4. Caching

Rendering the same content again and again puts a heavy load on the server. To counter such a case, caching is used. For example, an action render_one that is being called again and again would be a good candidate for caching. Indeed, caching is a requirement here.

In RoR caching can be done using the caching declaration. The caching can be page-level, action level, or both. To cache pages the declaration caches_page has to be used, and to cache actions the caches_action needs to be used. For example, in a blog management application, if the publicly viewable contents have to be cached the code would be:

class ContentController < ApplicationController
  before_filter :verify_premium_user, :except => :public_content
  caches_page :public_content

That ends the overview of the functionalities provided by the ActionController. In the near future I will discuss these in greater depth. But for now let’s move on to the next section, which features an example of using the Controller for processing.

Rails in the Real World 

As mentioned in the previous part, it is still not time for heavy-duty examples. They will be coming once the ActiveView and ActiveRecord have been discussed which will be covered in the near future. For this part, I will extend the example showing the time in the view created in the last part. If you remember, I created a controller having the following code:

  classSayController < ApplicationController
defhello
end
end

and the view(hello.rhtml) having this code:

  <html>
  <head>
  <title>Hello, Rails!</title>
  </head>
  <body>
  <h1>Hello from Rails! The time now is <%=Time.now%></h1>
  </body>
  </html>

But this is a bad design since the code for displaying date(in bold) is within view. View shouldn’t be doing this. So let’s move it to the controller because it is the right place for the code to be:

  classSayController < ApplicationController
     defhello
         @time=Time.now
     end
end

Now the current time value is stored in an instance variable time. Now it can be called from the view thus:

  <html>
  <head>
  <title>Hello, Rails!</title>
  </head>
  <body>
  <h1>Hello from Rails! The time now is <%=@time%></h1>
  </body>
  </html>

That’s it. In the next part I will be looking at the ActionView, the View Component of RoR. From then on I will be discussing the working of a real application, Library Management. Till then…

by  A.P.Rajshekhar