Rails scaffolds allows us to quickly create database backed MVC applications. However, scaffolding has limitations, such as generic views, and an inflexibility to change in the model.
We need to learn how to enhance and modify our scaffolded MVC-bundles. To do this we will need to learn more about:
*DRY = Don’t Repeat Yourself (a.k.a. Single Point of Truth)
This tutorial builds on the the blog engine tutorial.
Upon completion of this tutorial, you should be able to:
Web applications accept URL requests from browsers and respond with webpages. When using Rails, these webpages are generated by calls to specific Controller Actions.
Rails uses a routing system to map URLs to specific Controller/Action pairs. The routes are defined in a routing file :
/config/routes.rb
Our blog’s posts Controller (generated via scaffolding) will show up in the routing as:
resources :posts
See the comments above each of the posts Controller’s Actions to see which URLs they map to.
The routing defined by the resources method called within routes.rb is RESTful, meaning that HTTP Methods play a part:
REST in 15 Minutes (video)
It is very important to understand how Rails maps URLs to particular Controller Actions:
Rails Routing from the Outside In
By default the root URL of your Rails app maps to a welcome to Rails page. You can also map the root URL to a specific Controller/Action using routes.rb:
root to: 'posts#index'
The above route maps the root URL to the index Action of the posts Controller.
You can see your application routes using Rake from the command line:
rake routes > routes.txt
Now edit the routes.txt you just generated.
The columns in this file show the names of the routes, followed by their associated HTTP method and the URL, followed by the Controller/Action pair they map to.
Explore this file. Try to locate where the root route is defined, and note all the routes created for your posts controller.
Another way to see your application routes is to send a URL to your Rails server that does not exist. Your application routes will be displayed as part of the “Route Not Found” error page.
Let’s say you want to add a link from the show view of your posts Controller to the new action.
Although you could hand-code the link in HTML it would be easier to use rake routes to determine the name of the new route (new_posts) and then use the link_to helper in the show.html.erb:
<%= link_to 'New Post', new_posts_path %>
Rails Migrations allow us to make incremental changes to our Models.
To best understand Migrations please the Rails Guides page on Migrations.
Let’s say we want to add a new field to our Post model. Let’s say we want to record the ‘Awesomeness’ of each blog post. From the command line:
rails g migration add_awesomeness_to_posts awesomeness:string
This will create a new migration file in the db/migrate folder. Open and view this file to see the generated Migration.
To run this migration from the command line:
rake db:migrate
The naming in the rails g migration command is important. Whenever we want to add a new column to a table the command follows this form:
rails g migration add_column_to_table column:type
Where column in the name of the column to add, table is the name of the table to be modified, and type is the database of this column.
NOTE: If we want a newly added column to be set-able in a view form, it must be added as a white-listed parameter in your controller. See Strong Parameters.
Now that our blog Model has been updated we need to update our posts views.
In the new and edit views make use of a partial so that they do not repeat the same form code. We’ll add the following inside of the form_for block of the _form.html.erb file:
<p>
<b>Awesomeness</b> <br />
<%= f.text_field :awesomeness %>
</p>
The index and show views also need to be updated so that they display the new awesomeness field.
Let’s use a Model validation to constrain the possible choices for the Awesomeness:
ALLOWED_AWESOMENESS = [ "Awesome", "Almost Awesome", "Not Awesome" ]
validates_inclusion_of :awesomeness, :in => ALLOWED_AWESOMENESS
Now that we’ve constrained the possible awesomeness choices, lets have the new and edit views use a dropdown select box for awesomeness. Again we will edit the _form.html.erb file to make this change.
This file is a partial, a piece of ERB-enhanced HTML that can be used by multiple views. If you look in either new.html.erb or edit.html.erb you will see the form partial loaded as follows:
<%= render 'form' %>
Within the partial itself we’ll change the text_field builder for awesomeness as follows:
<%= f.select :awesomeness, Post::ALLOWED_AWESOMENESS %>
Let’s add a new action to our blog’s posts Controller in routes.rb by modifying the resources command:
resources :posts do
collection do
get :stats
end
end
Here we have added a stats Action that will respond to an HTTP GET request.
Our added Action deals with the collection of all posts. If we wanted to add an Action that dealt with a single post, we would replace collection with member.
Now that we’ve configured the routing for the stats Action we need to add a new stats method to the posts Controller, along with a new stats.html.erb file in the app\views\posts\ folder.
I’ll leave this as an exercise to the reader.