In my previous article, I wrote about the MVC model and how to create an application. Although it is not a requirement for this tutorial, I recommend taking a look at it. In this article, we will reinforce the understanding of the model but will now use Test-driven development (TDD) to create an app.
The objective here is not to deepen the understanding of TDD itself, but to understand the model, and the way we are going to program will guide us to understand it. In this article we will also go through the tutorial Step By Step Ruby on Rails Tutorial by Eduardo Baike and Kasey Champion.
TDD is a software development process where you start to write the test cases before the software is fully developed, then add features in order to pass all test cases. If you want to know more about TDD in Ruby on Rails, I strongly recommend the article Understanding Test-Driven Development with RSpec in Ruby on Rails by fellow Microverse student, Uduak Essien.
First things first, you must set up your machine. To do this, make sure that you have installed RoR according to the Odin Project tutorial on INSTALLING RAILS.
Now, let’s start running on your terminal the following commands:
{% code-block language="js" %}
$ rails new bookstore
$ cd bookstore/
{% code-block-end %}
Open the project in an editor (I useVSCode) then open the project running the server:
{% code-block language="js" %}
$ rails server
{% code-block-end %}
Next, open it in your browser (http://localhost:3000) and you should see that it is working.
Now, go to the Gemfile and add the gem rspec-rails in the development test group.
Follow the commands:
{% code-block language="js" %}
$ bundle install
$ rails g rspec:install
{% code-block-end %}
We are testing features, so go to the rspec folder and add a folder called features. Inside that, add the file called books_spec.rb and add the code:
{% code-block language="js" %}
require 'rails_helper'
RSpec.describe 'Book' do
context 'context' do
before do
book = Book.create(title:'The Lord of the Rings', author:'Tolkien')
visit '/'
end
it 'display a list books with the title and author' do
expect(page).to have_text('The Lord of the Rings')
expect(page).to have_text('Tolkien'')
expect(page).to have_link('New Book')
end
end
end
{% code-block-end %}
Now you can run the command to test it:
{% code-block language="js" %}
$ rspec spec/features/books_spec.rb
{% code-block-end %}
After running the test you will see the below error in your terminal:
What does that mean though?
It means we have no Book model for the path '/'. Pay attention to the error message 'uninitialized constant Book'.
So, to solve this let's create a model called ‘book’, setting up our table with two columns (title and author) running the commands:
{% code-block language="js" %}
$ rails g model book title:string author:string --no-test-framework
$ rails db:migrate
{% code-block-end %}
(Using the code --no-test-framework-- we are saying not to create a test file since we are creating our own.)
Now you can run the test again:
The error now says that we have no route for the path '/'. Also, be sure to pay attention to the error message that says to use the method GET to set up the route.
So, let's set up our routes to connect URLs to code.
{% code-block language="js" %}
Rails.application.routes.draw do
get '/', to: 'books#index'
end
{% code-block-end %}
Where:
Run the test again.
Now the error says that we don't have a book controller. Do you see that we are missing the C from the MVC?
{% code-block language="js" %}
$ rails generate controller books --no-test-framework
{% code-block-end %}
Now run your test again. You should see an error saying you don’t have any actions called ‘index’ in the controller.
{% code-block language="js" %}
class BooksController < ApplicationController
def index
end
end
{% code-block-end %}
As you see when you create a controller, we also are creating a folder called ‘views(empty)’.
{% code-block language="js" %}
<h1>Books</h1>
<p>The Lord of the Rings</p>
<p>Tolkien</p>
<%= link_to 'New Book', '/books/new' %>
{% code-block-end %}
{% code-block language="js" %}
class BooksController < ApplicationController
def index
@books = Book.all
end
end
{% code-block-end %}
{% code-block language="js" %}
<h1>Books <%= pluralize(@books.length, 'Books')%></h1>
<tbody>
<% @books.each do |book| %>
<table>
<tr>
<th>Title</th>
<th>Author</th>
</tr>
<tr>
<td><%= book.title%></td>
<td><%= book.author%></td>
</tr>
</table>
<% end %>
</tbody>
<%= link_to "New Book, "/books/new" %>
{% code-block-end %}
However, the data we are testing is not from the database. If you run the server and open it in your browser, you will see it is empty.
Since the database is empty we have to create a method to populate it, this method will be called new. However, we are working with TDD, so let's create the test first. Follow the below steps:
{% code-block language="js" %}
require 'rails_helper'
RSpec.describe 'Book' do
context 'context' do
before do
book = Book.create(title:'The Lord of the Rings', author:'Tolkien')
visit root_path
click_link('New book')
end
it 'page to create a new book' do
expect(page).to have_field('title')
expect(page).to have_field('author')
end
end
end
{% code-block-end %}
{% code-block language="js" %}
Rails.application.routes.draw do
root 'books#index'
get 'books', to: 'books#index'
end
{% code-block-end %}
Before we test the new feature, let's change the books_spec.rb file by replacing the code visit '/' to visit root_path and test it. Now we can test the new feature running the command:
$ rspec spec/features/new_books_spec.rb
You will see the error regarding no route matches. Does it sound familiar?
{% code-block language="js" %}
Rails.application.routes.draw do
root 'books#index'
get 'books', to: 'books#index'
get 'books/new', to: 'books#new'
end
{% code-block-end %}
{% code-block language="js" %}
def new
@books = Book.new
end
{% code-block-end %}
For a full-video walk-through of this concept and tutorial, you can view the video below:
Now you should have a better understanding of the MVC model by using TDD. You are going to need to repeat the steps over and over again if you want to create new features like create, update and destroy. From this tutorial, you can also see that TDD is a great option to guide us through adding features.
As always, remember to check the Rails documentation.
Happy Coding!
Career advice, the latest coding trends and languages, and insights on how to land a remote job in tech, straight to your inbox.