Project Ramon

A learning journey from a Ruby noob perspective

Rails Routing: Conventions are Our Friend

rails_routing2_header_img

Yesterday we covered some basics about Routing in Rails, described what a resource actually is, and saw a few illustrations that showed some of the power behind using RESTful Rails conventions when sending and receiving requests.

Today, continuing from Obie Fernandez’ book: The Rails 3 Way, we’ll take a closer look at whats actually going on when we use Rails’ routing conventions. Remember how we were calling the same path for different REST actions yesterday? Well this next section is geared towards understanding this topic a little better.

CRUD Routing

The REST facility of Rails allows us to use the same path call for our routing purposes of multiple actions. The way we can do this is by using the same path call, but stipulating different HTTP verbs.

Here’s a quick example:

From line 2 above, we can see that the HTTP verb associated with each route created has been explicitly set, it is now clear to see how we could call users_path in our code and receive two different HTTP responses based upon the different verbs (GET & POST) used by the route.

Rails does not force us to use RESTful conventions, we could create a route that maps to any controller action, with any method name we desire to write in our controller.

The powerful benefits of going with the RESTful conventions provided, is that we gain an advantage of perceiving our app’s communication abilities through a standardized set of controller action names and an added efficiency bonus of having a technique for creating bundles of named routes that automatically point to a specific set of actions.

Routing Conventions

If you’ve ever built a Rails app, you’ve probably utilized their automatic route generating code
resources :users, which will create 4 named routes, that map to 7 controller actions. Typing rake routes in your console, will provide you with a list of all of your routes.

rails_routing2_img1

Above is an illustration snippet from my routes. The first part of the line is the helper method that is used to route the file and the second part of the line (the words in all caps) are the HTTP verbs. So from the illustration above, we can see that we could call university_teams_path  and could expect to be routed to either our teams#index or teams#create view templates depending on whichever HTTP verb is either explicitly expressed by us or implied by convention  in Rails.

An example of how an HTTP verb would be implicitly expressed would be how the default HTTP verb in Rails is set to GET, another would be how our create action automatically uses POST to PUT or commit user data from a form into our database to be used later as a representation of a resource composite.

New/Create & Edit/Update Revisited

The create and update actions typically involve form submission.

So they really involve two requests each:

  • Step 1: Display a form to GET results, either from client submission or from the database
  • Step 2: Process the form input, either using the POST verb to commit a new database submission or using the       PUT verb to update a current record in the database

So both the create and update are closely associated with a pair of preliminary actions. ‘new' is associated with create and ‘edit' is associated with update.

Nested Resources

There will undoubtedly be a time when associating resources in your project becomes necessary. Some examples of this could be a program that keeps track of who sold the most treats at a bake sale. So the application calls for desserts to be associated with each user present.

Heres one way our route setup could look taking the above feature to mind:

What the second portion of the above illustration is attempting to convey is that any time we want to do something to a dessert, we will need to include which user the dessert resource belongs to. Or as The Rails 3 way puts it, we begin treating desserts as a user/dessert pair.

Once we created our nested resource of users/desserts earlier we now have paths like in the above illustration. These paths, once nested will contain the parent and descendent nested resource and provide a nested path as we see above. These nested urls give us immediate access to the user’s id through the parent resources’ params[:user_id].

In order to receive the benefits of this we must remember that when using a nested desserts resource url, to provide a user object passed in as an argument to the nested path like so: user_desserts_path(user) or new_user_dessert_path(user).

I have been enjoying the process of getting a better grasp of Rails routing, and will be continuing this topic until I can confidently write controllers without errors from NilClass and such. If you have anything to add to this post, feel free to comment!

Advertisements

Categories: Uncategorized

2 replies

  1. Great progress! Three small comments:

    1. university_teams_path vs. university_teams_url is NOT about picking a different HTTP method, but simply by using a relative vs. absolute URL (absolute – starts with http, relative just starts with a slash /)

    2. form_for @user, url: user_path(user) — it’s enough to just say form_for @user ; one thing to remember with nested resources is that you’ll need to say sth like:

    form_for [ @user, @dessert] do |f|

    or

    form_for [ :admin, @user ] do |f|
    when you use namespaced routes

    3. the ‘new’ and ‘edit’ URLs aren’t really REST-ful strictly speaking. REST does not say anything about them, there are no ‘new’ and ‘edit’ actions in the REST vocabulary. 100% REST-ful version would probably be more like ‘user_creation_form’ (vs. user_new) and ‘user_change_form’ (vs. user_edit) – because here we are ‘showing’ (that’s RESTful) forms that are used to create/edit a user. But that’s just a minor thingy 🙂

    If you’re suffering from Nil errors in your controllers: one trick I’ve been doing is using filters to guarantee that objects exist. For example, each edit, update, show and destroy action defined in a UsersController, requires an existing user object. So instead of grabbing it everywhere, you can say:

    before_filter :resolve_user!, only: [ :edit, :update, :show, :destroy]

    # and then

    private

    def resolve_user!
    @user = User.find_by_id params[:id]
    redirect_to users_path unless @user
    end

    in this way, you’ll get the @user in each of these actions ‘for free’. I know people in the Rails community have mixed opinions about filters, but I think it’s a pretty useful approach.

    Great work Ramon, I’m cheering for you too!

  2. Thank you for those 4 points of guidance. I will make the edits in my blog and start implementing filters in my controllers. Have a great weekend Marek!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s