Friday, January 22, 2016

Mutatis Mutandis (1)



As I said in the last article “Do not change conventions without good reason” (http://rubyofftherails.blogspot.com.br/2016/01/do-not-change-conventions-without-good.html), there are certain things one can change in the conventions of Rails without doing any harm.
 
In fact, there are certain things you may need to change in order to keep the principles of Rails, like DRY, as I already said in my previous article “Rendering and the DRY principle” (http://rubyofftherails.blogspot.com/2016/01/rendering-and-dry-principle.html).

That's why I opted for the latin expression "mutatis mutandis" for the title of this series of articles. For those who never studied latin at school, "mutatis mutandis" means "changing what must be changed" or "when all things needed were changed".
 
One of the things you may, and sometimes need to, change are the routes in config/routes.rb.
 
If you used scaffold to create your entities, your config/routes.rb probably contains now a list of things like
 
resources :customers
resources :products
resources :users
resources :photos
 
This means Rails will add, by default, a set of routes to make your job easier. Taking the case of resources :photos, the resulting routes will be
 

 
If you wish to change these routes according to your needs, no problem. Provided, of course, that you create all routes necessary to you application and include all the parameters needed, there is no problem in changing this particular default. On the contrary, personalize your routes is perfectly normal and sometimes necessary. Let’s consider the following situation.
 
You are creating an application where a certain photo must only be shown to authenticated people. And you are using a token authentication. Then you may have to change the route /photos/:id to a more complex route /photos/:id/token/:tkn.
 
Same happens when you sent your user who forgot his password a link to create a new password by e-mail. This kind of e-mail  usually has an expire time which is persisted in a table in your database. Maybe you created columns in your users table (I do NOT recommend this) to indicate a certain user required a password change and when. But if you learned well how to model a database, you haven’t done that! You certainly have a table, say changepass, with three columns just for these situations: id, the primary key of the request; user_id: a foreign key referencing the user asking for a password change; and expire_time, the time the request will expire. Then you may need to add a totally different route to your resources :users, say
 
/users/changepass/:reqid, to: ‘users#changepass’
 
And then you’d create two methods, changepass and expired_request? in your app/controllers/user_controller.rb
 
def changepass
    request = Changepass.find(:reqid)
    if (expired_request?(request.expire_time))
        render ‘changepass_screen’
    else
        render ‘expired_request_screen’
    end
end
 
def expired_request?(exp)
  Time.now > exp
end
 
As you may see, it is possible to create new routes. In the next article I’ll write about ignoring the routes automatically generated by resources and creating your own set of rules.

See you.