Coding Bootcamp Week 3: ALPHA Camp (Singapore)
I was initally unclear about the basic definitions so let define it here.
Ruby is a programming language whereas Rails is a gem, or a Ruby library. Specifically, Rails is a web framework that helps make web applications by providing classes for saving to the database, handling URLs and displaying HTML (along with a webserver, maintenance tasks, a debugging console and much more).
So, Ruby on Rails = using Ruby language on the Rails framework.
The Rails philosophy includes 2 guiding principles:
- Don’t Repeat Yourself (DRY): By not writing the same information over and over again, code is more maintainable, more extensible, and less buggy.
- Convention Over Configuration (COC): Rails has opinions about the best way to do many things in a web application, and defaults to this set of conventions. Hence it has many sensible defaults and this speeds development. e.g. Plural naming for the Controller versus Singular naming for the Model.
Setup for our first project from the terminal (already installed Ruby and other necessary tools like RVM):
- $ rvm gemset create project_name
- $ rvm gemset use project_name
- $ rvm gemset list
#to check if project_name is the gemset being used
- $ gem install rails
- $ gem install bundler
- $ rails new project_name
- $ cd project_name
- Create .ruby-gemset
#open file and use the name of the project as the name of the gemset
- Create .ruby-version
#open file and specify the verison of Ruby to use and save
- $ bundle install
#to install all the ruby gems required
- $ rails server
#to get server up and running on http://localhost:3000.
This is the display on the browser if nothing goes wrong:
Rails Console. IRB is the interactive Ruby console. Rails has a special IRB console to access the web app as it is running (excellent for live debugging). It can be accessed from the terminal with the command $ rails console or $ rails c.
Class and table names are important. Rails has certain naming conventions. Rails has a pluralization engine to figure out what object maps to what table. Model class name is singular whereas database table names are plural.
Model Class: Cat
Table name: cats
Model Class: Person
Table Name: people
Also, for names with two words, the model naming uses CamelCase whereas the table name uses snake_case (all lowercase):
Model class: ViewCounter
Table Name: view_counters
Understanding The Model-View-Controller Architecture
Rails function on the MVC pattern. The underlying concept: to separate the data, logic, and display layers of the program. This splits functionality cleanly.
- Models are classes that interact with the database. Any database related actions (such as modifying data before it gets saved inside the database) should be placed here.
- Controllers handle decisions from the browser and connect the model with the view. In Rails, controllers are implemented as ActionController classes. The controller should not include any database related actions. This should be handled in the proper model.
- Views is the presentation layer which is what the user sees. This displays the output, usually HTML.
- Routers map HTTP requests from the browser to a Controller#action via the HTTP verb (
GET, POST, PUT, DELETE)and the URI of the HTTP request.
Current best practices include:
- fat model and skinny controller
- business logic should always be in the model
- the view should have minimal code
- Use helpers!
The week’s assignment would be to create a simple blog application.
Simple Blog Application (Manual method)
I will approach this by first drafting a story outline which covers all CRUD operations. Then, I will create the necessary based on the story flow.
In total, we need:
- 7 Routes
- 1 Controller with 7 actions defined
- 4 View templates (new, show, index, edit)
- 1 Model (Article) with associated migration and schema files
First, to configure the Rails router (config/routes.rb). Rails has a
resources method which can be used to declare a standard REST resource:
We can enter
$ rake routes in the Terminal to view the 7 routes generated:
#index, #create, #new, #edit, #show, update, #destroy
Next, we need to generate the controller:
$rails generate controller Articles
ArticlesController is a class that inherits from
ApplicationController. CRUD (Create, Read, Update, Destroy) methods will then subsequently be defined to perform CRUD operations.
Create Views (in app/views/articles):
To allow the user to key in an article entry, we need to add a form into the new.html.erb page. We can use a Rails helper method called
Inside the block for the form_for method, the
FormBuilder object - represented by
f - is used to build three labels and three text fields, one each for the title, author and text of an article.
Finally, a call to
submit on the
f object will create a submit button for the form, which will send a
POST request via the
articles_path (specified at the top by indicating url:
articles_path) and this is mapped to the
When the form is submitted, the fields of the form are sent to Rails as parameters. These parameters can then be referenced inside the controller actions. For the
createmethod above, Article.new creates an instance of the class Article which takes in article parameters. This instance is saved into an instance variable prefixed with
@ . We do this because Rails will then be able to pass instance variables to the View.
In order to ensure that our form receives only parameters which we expect to receive (non-malicious content), we have to whitelist our controller parameters to prevent wrongful mass assignment. In this case, we use require (for the model) and permit (model attributes of :title, :author and :text) like so:
@article = Article.new(params.require(:article).permit(:title,:author,:text))
With that, Action Controller parameters are forbidden to be used in Active Model mass assignments until they have been whitelisted. This is a security practice to help prevent accidentally allowing users to update sensitive model attributes. In addition, with require, parameters flow through a predefined raise/rescue flow that will result in a 400 Bad Request being returned if not all required parameters are passed in.
Also, this whitelisting method is often factored out into its own private method so it can be reused by multiple actions in the same controller, for example
After a user clicks on the create/save button, the #create action leads to the article being saved into the database. Then, a GET request is sent to redirect to the show page (articles/:id) which shows the user the specific article he/she just entered.
This requires a model to be first created in order to save the article entry into the database:
$ rails generate model Article title:string author:string text:text
Models in Rails use a singular name, and their corresponding database tables use a plural name. With that command we told Rails that we want an
Article model, together with a title attribute of type string, author attribute of type string and a text attribute of type text. Those attributes are automatically added to the
articles table in the database and mapped to the
Article model. A database migration file inside the
db/migrate directory is also created (file is named according to date and time created):
In the migration file, a method named
change will be called when we run the migration. This will create the table with the table field we specified. The change method is reversible. Meaning if we migrated changes and would like to undo it, it is possible. The t.timestamps attributes is a Rails sensible default. It actually represent 2 attributes: updated_at and created_at.
Rails Migration is a set of database instructions that allows us to use Ruby language (rather than the database lanaguage SQL) to “migrate” the database from one state to another (e.g. create and modify database tables by adding new columns). Each migration is a new ‘version’ of the database.
In order to create the articles table columns in the database, we run this command:
$ rails db:migrate
Moving on, we now require the
show action +
index action +
Article.find finds the article of interest using
params[:id] and is then assigned to an instance variable. Lets say for example, the article :id is 1 (URI pattern: articles/1). When we use it in the Views (
show.html.erb), we reference to it using:
<%=@article.title%> and this will display article 1’s title.
%>wrap Ruby code whose return value will be output in place of the marker
%>wrap Ruby code whose return value will NOT be output
Now, we will need a way to list all our articles. We do this by creating an
index action and then creating an
<%= link_to <text>, <path_name> %> generates an anchor tag in the html.erb file.
Lets see how things look for now:
A user can enter the URL via
articles/new to key in a new article:
After hitting the ‘Save Article’ button, the user can view the article:
The user can then view a list of all articles via the
So far so good. We have the
#index, #create, #new, #show actions. Now to add
#edit, #update and #destroy.
The edit view will contain a form similar to the one we used when creating new articles. The difference lies in the routing URL and HTTP request method. The first parameter of
form_for can be an object, say,
@article which would cause the helper to fill in the form with the fields of the object. Passing in a symbol (
:article) with the same name as the instance variable (
@article) also automagically leads to the same behavior.
The new method,
update, is used when you want to update a record that already exists.
We don’t need to add a view for this action since we’re redirecting to the
We add a ‘Destroy’ link at the index page for each article. But we will use
link_to in a different way. The
data:options are used as HTML5 attributes so that when the link is clicked, Rails will first show a confirm dialog to the user, and then submit the link with method
rails-ujs which is included in your application's layout (
app/views/layouts/application.html.erb). Without this file, the confirmation dialog box won't appear.
Finally, we add relevant links to each page so to allow the User to navigate easily throughout.
Index page now:
Destroy confirmatory dialog:
So that’s a wrap! A simple (ugly) but functional blog application with CRUD operations. Added a little bootstrap and it looks more presentable:
I tried the Scaffold method to create the simple blog application just to see what it does and here’s it:
Simple Blog Application (Scaffold method)
Our instructor pointed out that the Scaffold method creates a whole set of files, some of which we will not need and may not want. Also, as a beginner learning rails, I would want to learn the codes and build the app from scratch (above).
Nonetheless, here’s my experiment using the Scaffold method. A similar endpoint but a shortcut method. I created a new folder for this and decided to name it as Answers (because it seemed like a quick solution to the simple blog application haha).
$ rails g scaffold Answer title:string author:string body:text
Above is the Answers database migration file created with the fields I specified.
The next step would be to run the migration in the terminal:
$ rake db:migrate
This sets up the database for Answers. The database being used would be the default SQLite3 database for Rails. This database is not for major production applications, but it is suitable for testing and for the purpose of this simple blog application.
Next, we would need to set the root route to be the Answers index page. This is done in the config/routes.rb file. Add root “answers#index” under the resources :answers text in the config/routes.rb file to set the home page to the Answers index view. The view is found in views/answers/index.html.erb. (Pre-populated view by using the scaffold method).
We will next run the command: $ rails db:migrate
Run rails s in the terminal and go to localhost:3000 in the browser.
This is the view rendered in the browser:
Clicked on “New Answer” and a new page is rendered:
Here, a GET request is made to render the new.html.erb page with a form for the user to enter posts. Subsequently, when “Create Answer” is clicked, it will trigger a POST request to record the data in the database and then a GET request to redirect the user to /answers/:id page.
Clicked on “Edit”:
This triggers a GET request from the broswer which is routed to the Answers controller and edit action. The edit.html.erb view is rendered with a form (with previous pre-populated post entry) to allow for editing.
Edit page and click “Update”:
Back to Index page:
$ rake routes
Answers Controller action methods:
Legit! The scaffold method builds a simple blog application in 5 minutes. Keeping in view for future use.
That concludes the simple blog application assignment for the week and some of the basic Rails concepts covered. Much more to learn!