Creating a Simple Model and Database

Creating a basic model and corresponding database is fundamental to creating many interactive websites, unfortunately, doing so is not straightforward.  It involves creating files in Ruby on Rails and running a command to use that model to create the actual SQL-flavored database structure … the M of the MVC design pattern.  You also need to actually add values to the dabase (aka, you need to seed it), create web pages that show that data (the V of MVC) and create methods that link the two (the C of MVC).  And while there are many references for how to do any one of these steps, I have found it difficult to find a single resource that pulls it all together.  

Hence, I have created this tutorial as an example.

If you want to change the name of the model, remember that you will need to be consistent throughout!!


I include these for you to review … possibly after you have created one model and database and can put the instructions in perspective.

  • Hartl 2.3 unfortunately uses the scaffolding to do too much work, and it depends upon the relationship between a micropost and the user that created it.
  • Hartl 13 depends upon the micropost being associated with the user that creates it
  • Hartl 6 and 7 and 13 have the information you need, but there’s a lot more detail than required for a simple model and database
  • Step-wise instructions, that are actually quite good,  for how to seed a database from a .csv file:


  1. Create a simple model that has no associations with any other model (for now)
  2. Run the migration to create the database
  3. Seed the database from a .csv file
  4. Display the resulting database on a page
  5. Do the migration and seed on Heroku too
  6. Change controller and view to put the data where I want it to appear

Main Dish Model

This is an extremely simple model that will create a single table in the database and let you display that information on a page.   

id integer
name string
created_at datetime
updated_at datetime

0) Create a New Test App

It is not required, but you might want to create a new app to use as a sandbox/playground for this exercise.  Alternatively, you can simply add it the new table and views to your existing individual project.  You should create a new branch in git so that you can ignore (and possibly delete) it after this exercise.

1) Generate the Model & Create Database

To start: create a new branch in git!!!

Then, you can generate the model:

rails generate model Maindish name:string

This creates the first migration, the model file (maindish.rb), a model test file, and a fixtures file.  No controller or view is created automatically.  

Since at this point, I am not relating tables in the database, I’ll just do the migration to create the database:

rails db:migrate

2) Initial Automated Testing

For now, validations are minimal and so are tests.  We only need to test that the maindish has a name, really, but just to make sure that the web pages look good, let’s make the maindish name no more than 80 characters (following Hartl 13.1).  Both of these tests are confirming that our model’s data will be valid when stored in the database, so we need to flesh out the tests in test/models/maindish_test.rb, which should have been generated when we created the maindish model itself.  

We will first write tests that should fail (because we haven’t added any constraints to the model yet).   So open test/models/maindish_test.rb and within class MaindishTest add the code for these two tests :

test "should not save maindish without a name" do

   maindish =

   assert_not, "Saved a maindish without a name"


test "name should not be longer than 80 characters" do

   maindish = = "a" * 81

   assert_not maindish.valid?, "Maindish name too long"


Note that each test must start with the word “test”.  I did that wrong the first time I tried writing tests ….

If you run rails test at this point, the tests should fail because the model allows what we don’t want to happen!!  This is actually a good thing because we know that the tests will catch errors.  Now, we fix the code so that it won’t let the mistakes through to the database.  

In app/models/maindish.rb, add a line to the model that will both validate that the name has some content and that it is short enough:

class Maindish < ApplicationRecord

validates :name, presence: true, length: {maximum: 80}


Once that is saved, run rails test again.  This time, the tests should pass because the model validation code won’t let the mistakes through.  

(See for more information on writing tests. ) 

3) Have Data Show on a Webpage

The next important step for the simple menu is to have the maindishes, if any, appear on the a page.  For now.  Eventually, I envision a menu.html page that displays records from several fields, but this is a start toward that functionality.  This is a simplification of Hartl 13.2.

We don’t need to reset and reseed the database at this point, but we need to create a controller for Maindishes.  (I took a gamble and pluralized it since that seems to be the convention.)

rails generate controller Maindishes

Which created a controller, a set of views, a test, a helper file, javascript, and a stylesheet

What we want to do is 1) seed the database with a few maindishes so that I can, 2) display all maindishes as a test and then 3) make the random menu page show a single, randomly chosen maindish

In the db/seeds.rb file, I created three maindishes …. Such as Maindish.create(name: ‘Green eggs and ham’)

Then, I ran rails db:seed

You can verify that the seeding worked either by starting the rails console or by looking at the database with the SQLite3 database inspector.  If you want to use the rails console, you need to be sure you have gem ‘rb-readline’ installed in the Gemfile.

To display all the maindishes on a page, I modified the controller to create an index method that gets all of the maindishes from the database and puts them into an instance variable.

class MaindishesController < ApplicationController

   def index

      maindish_list = Maindish.all

      @maindishes = maindish_list


I picked index as the method name because I plan to put this on the index.html page in the maindishes view.  

I created the index.html.erb file to show the whole list.  It’s very primitive at the moment …

<% provide(:title, ‘Maindishes’) %>

<h1>Main Dishes</h1>


<% @maindishes.each do | maindish | %>

<li><%= %></li>

<% end %>


I modified the routes.rb file to include a line to let it know that the standard REST file mappings should happen for the maindishes table/model/resource

resources :maindishes

Run the test suite to make sure you haven’t broken anything along the way, then start the server and navigate to the index file for maindishes …..


And it should work!!

4) More Realistic Dummy Data

Next step is to seed the database from a .csv file (the original instructions are at:

Create a directory/folder called seeds inside of the lib directory/folder and create a .csv with your data inside of that directory.  Make sure you have columns for each data field that will be in your database.  You can use column headers and those will not become part of the database, but should help identify which fields for each row in the spreadsheet should map to the row in the database. 

The seeds.rb file should end up looking like this:

require 'csv'

csv_text ='lib', 'seeds', 'maindishes.csv'))

csv = CSV.parse(csv_text, :headers => true, :encoding => 'ISO-8859-1')

csv.each do |row|

   m = = row['name']

   puts "#{} saved"


puts "There are now #{Maindish.count} rows in the Maindishes table."

For testing, I just had one column, but multiple columns should work.  Also, if you want to know what each line means, refer to the original instructions.  

When you have created the file, do rails db:seed to seed the database.  

To check that this actually worked, I went into the rails console to query the Maindish.count and check what Maindish.first was in the database.  To test it repeatedly, I dropped the database with rails db:drop and then rails db:migrate to rerun the latest migration file.  If you do rails db:reset, it will drop, migrate and rerun your seed in one step, which I didn’t want since I wanted to be sure that my database information was gone entirely before I seeded it again.    

After you have it running on your local machine and have run your automated tests (which should pass), you can push it to both GitHub and Heroku.  Remember, after pushing to Heroku, you will need to run the database commands AGAIN on Heroku to create (or modify) the database and seed the database from your seed.rb file:

rails db:migrate

rails db:seed

Note: If you don’t want to generate any data on your own, you can use the Faker gem to generate bogus content (see instructions at:  This gem can create realistic data for a wide range of data types and situations!!

5) Display a Single, Random Main Dish on a Different Page

Ok, this is all a good start, but what I want is to get a single, random main dish and display it on the home page.  Or maybe on a menu page as a precursor to having multiple dishes displayed to create a random menu.  I want to break free of the automagic and put information from the database where I want it.  This is good practice to confirm that you understand the ideas.

First step is to change the controller that is associated with the page where I want the data to appear and change the method that runs that particular page.  In my case, I changed the static_pages_controller.rb and the home method to create an instance variable that contained the information that I wanted to display:

  def home

      maindish_list = Maindish.all

      dishNum = (0..maindish_list.length-1).to_a.shuffle.first

      @maindish = maindish_list[dishNum]


  Next, change the view where you want to display the data (home.html.erb) by adding a line such as:

<p>A random main dish for your consideration: <%= %></p>

NOTE: I ran into trouble with Heroku when I tried to migrate and then reseed the database.  Since it is a “production” database, it didn’t want to lose the values currently in the database.  It would let me do rails db:seed, but that duplicated the values in the Maindishes table.  You need to make it reset the database using a pg command to do so with these instructions:  Since I am not using the command line tools for Heroku, I used the web based Heroku tools:

  1. Log into Heroku and pick the app that you are working with
  2. Under “Installed add ons”, you should see Heroku Postgress.  Click that add on to get to the configuration menu.  
  3. Pick the “settings” tab
  4. Pick “reset the database”
  5. It will ask you if you’re really, really sure you want to do this.  Confirm.  This will dump all of the data in the database
  6. Get back to the dashboard for the app you are working on
  7. Under the “More” button, pick “run console”
  8. Run “rails db:migrate”
  9. If applicable, run “rails db:seed” to re-seed the database.

The command line commands can be found in Hartl Chapter 13.