Thursday 18 March 2010

Rails - Day 7 - Our first View

Rails  - Day 1 - The RubyGem Love Story
Rails -  Day 10 - Testing Rails Controllers
Rails -  Day 13 -ActiveRecord Relationships Part II
Rails - Day 15 - Rails Forms Part II

In the last post, I introduced the blueprint CSS framework, HAML, SASS and last but by no means least Compass.

Compass allows us to harness the power of a CSS framework like blueprint with the programmability of Sass and HAML. In this post, I want to show how to set compass to compile your sass files into css and also fire up a simple view.

I have got to the point now with Compass, were I really do not understand how I ever did CSS without Compass and sass.  I also do not think I would have stayed with Blueprint without Compass.

Now without further a do, let us install all the bits into our rails application.

Requirements

  • HAML/Sass Gem
  • Compass Gem
  • Configure Rails for Haml
  • Configure Rails for Compass

Thankfully those very smart people from compass have come up with a rails installer that we can use that will get the bits for us and give us a wizard like experience to configure our rails app.

If we were creating a new rails project from scratch, we would create it with the -m switch pointing to the compass installer.

rails datacapturer -m http://compass-style.org/rails/installer

As we have already created our project, we are going to issue the following command to install compass:

rake rails:template LOCATION=http://compass-style.org/rails/installer

The compass installer will then ask us the question:

What CSS Framework do you want to use with Compass? (default: 'blueprint')


We can just press enter to keep the defaults.  We will then be asked to confirm:

Where would you like to keep your sass files within your project?


Where would you like Compass to store your compiled css files? (default: 'public/stylesheets/compiled')
We can just press enter to keep the defaults, so we just press enter.  We will then be asked to confirm:



We can just press enter to keep the defaults.  We will then be asked to confirm:

The installer will then install the requirements listed above and execute the various commands to configure both haml and compass for our application:


I have done the steps that the pre-installer performs for us by hand and although not overly complex, the installer makes it all the more easier.

As the installer says, we are ready to have fun.

So what has the installer done, if we look at our rails project directory and in the app folder, we can see the following files have been added:



Three sass files have been added, ie.sass, print.sass, screen.sass and to the app/stylesheets folder and a _base.sass file has been added to the app/stylesheets/partials folder.

You will also see that under the public/stylesheets directory, an empty directory has been created called compiled:


Sass compiles down to regular (ugly) CSS.  

So how do we get the sass to start compiling down to css?

Thankfully compass comes with a command line tool.  One of the options of the command line tool is the --watch or -w switch.  When the compass command line tool is invoked with this switch, the tool will monitor the current project for changes in the sass files and will then compile the sass down into css.  So without further a do, let us start Compass monitoring, we cd into our project directory and issue the compass -w command which will generate the following response from compass:


You can see from the above that it has created 3 files that match our sass files in the public/stylesheets folder, ie.css, print.css and screen.css:



Any changes to the sass files will result in the CSS being compiled.  A quick look at the screen.css file reveals that the sass has generated a whole raft of css for us.

I think it is high time I created a view to hopefully start bringing some of this together.

First of all, we want to at least check that we can bring up the default rails template web page.  In order to do this, we need to boot up our development web server.  WEBrick is the rails equivalent of the Web Developer Server that we use with ASP.NET named cassini.  Like Cassini, we access it via localhost on a high-numbered port that doesn't interfere with other services on our machine.  WEBrick starts on port 3000 by default.  We start the web server with the ruby script/server command:


if we type the following url into our browser, http://localhost:3000/, we are greeted with the following page



If you remember for part 4, one of the files that was generated for us by the script/generate resource users command was the users_controller.rb file which is of course our users controller class.  I am hoping that most people now understand the concept of MVC by now but if not, MVC uses a particular magic called routing to route our http requests to methods on our controller classes.  Think of routing as a type of URL rewriting that will break down the url and extract the correct controller class and then invoke the correct class method.

If you have ever written an HttpModule or such like in order to achieve Url rewriting, you can breath easy.  We merely configure the routes.  All the other plumbing is done for us.

I now want to show that the script/generate resource users command has updated the routes.rb file correctly.  I want to test out the index action of the UserController is working.  In order to do this, I add a method named index to my UsersController class:


As you can see, we simply want to output some text on the page.  Typing in the url http://localhost:3000/users, gives us the following result in our browser:

This brings us on nicely to how exactly the url http://localhost:300/users is routed or mapped to the index method of our UsersController class.  

Rails and REST

I mentioned in an earlier post about the resource generator.  Rails uses the word resource in the context of a REST resource.  The resources are the nouns of your application, an example of such a noun in our application is the User resource we have generated for this example.  If the resources are the nouns, then the verbs are the HTTP verbs:

  • GET is used for safe operations like Read
  • POST is used for unsafe operations like Create.
  • PUT is used to create or update a resource at a specific URL.  It changes or creates a resource.
  • DELETE is the most obviously named verb as it deletes a resource at a specified URL.

I am personally not a huge fan of REST.  The above form a minimal set and it is only in more recent times that browser vendors have implemented PUT and DELETE.  It is also worth noting that HTML or at least pre HTML 5 does not support PUT or DELETE either.  So in order for rails to conform to the REST standard, it uses a hidden form field to simulate PUT and DELETE requests.  Thankfully you do not have to conform to REST practices 100% in rails but to try and fight it would be very much swimming against the tide.  On the plus side, REST gives you a consistent interface to program against.

If we can put my cynicism to one side, you can see in the table below how rails has taken the four HTTP verbs described above and maps them to seven controller actions and they will appear on our UserController.  Actions in this context are the public methods of your controller:

Rails ActionDescriptionURLHTTP Verb
indexA collection of Users/usersGET
showA User/users/123GET
newA form for creating a new User /users/newGET
createWhere you submit the new User form /usersPOST
editA form for editing an existing User/users/123/edit GET
updateWhere you submit the edit User form/users/123PUT
destroyWhere destroy (delete an existing User)/users/123DELETE
   
Notice how the URLs for the show, update and destroy are identical but use different HTTP verbs.

You can see below the line that the script/resource generator has added to our routes.rb file that will hook up these 7 out of the box methods:


Custom Routing

We are of course not confined to these 7 actions in our controllers but in a way, it is nice to find this level of consistency to have the same 7 actions that do the same seven things on each controller.  

We can of course add our own by updating the routing file.  Let us say we wanted to add an action that would display all our users that were enabled in our application.  This is another good example of the workflow of rails.  We currently do not have an enabled field on our user object so we can create a new migration with the following command:


We then update the newly created migration file 20100310051724_add_enabled_to_user.rb to the following



We then run rake to update our schema:


We can then update our seeds.rb file with the following code that will now, delete all users in the database and then update any seed data with the new enabled flag:


OK, now let us add a show_enabled action to our controller:



The observant of you might be asking where the find_all_by_enabled method has come from but I will leave that as an exercise for you the reader.  Needless to say, we did not write it.

Now, if I type the url http://localhost:3000/users/show_enabled into my browser, I get the following response:


So how do we map this show_enabled_action in routes.rb?

In rails it is possible to add what are known as member routes such as:


This will enable rails to recognise URLs such as /users/1/preview/ using the GET HTTP verb or as in our show_enabled example action, we can use a collection route that looks like the following:


Hopefully this has shed some light on how the routing in rails works.  

In the next post, I want to get back onto the power of HAML, SASS and Compass.









No comments:

Post a Comment