Basic CRUDy MVC

CRUD stands for Create, Read, Update, and Delete.

When we talk about CRUD we mean the basic functionality needed to be able to create objects, read those objects, update the data in the objects, and delete them.

In Rails, CRUD has been replaced by REST as the preferred pattern, although they are similar.

The App

Create the App

Run the rails command to create your rails project. In this case, the project is named “robotville”:

shell$ rails robotville
   create  
   create  app/controllers
   create  app/helpers
   create  app/models
   create  app/views/layouts
   .
   .
   .
   create  log/test.log

This will create the folder “robotville” in your home directory with a skeleton rails project.

For the rest of this tutorial, we will assume that all shell commands are run from within the rails directory (ie “robotville”). To change the current directory to be “robotville” run this command:

shell$ cd robotsville

The only thing you need to configure for your rails application at this point is how to find the database. Edit the file database.yml (found in the config folder) and paste in this content:

codetitle. config/database.yml

development:
  adapter: sqlite3
  database: db/development.db

test:
  adapter: sqlite3
  database: db/test.db

production:
  adapter: sqlite3
  database: db/production.db

To test if everything is working so far, run this command in the shell:

shell$ rake db:migrate

If you get no errors, then your database configuration is correct.

The model

Generate the model

$ script/generate model Robot
    exists  app/models/
    exists  test/unit/
    exists  test/fixtures/
    create  app/models/robot.rb
    create  test/unit/robot_test.rb
    create  test/fixtures/robots.yml
    exists  db/migrate
    create  db/migrate/005_create_robots.rb

For now, we don’t need to modify the model. It looks like this:

class Robot < ActiveRecord::Base
end

Create the migration

codetitle. db/migrate/005_create_robots.rb

class CreateRobots < ActiveRecord::Migration
  def self.up
    create_table :robots do |t|
      t.column :name, :string
      t.column :power, :string
    end
  end

  def self.down
    drop_table :robots
  end
end

Create the fixture

Fill out our test data in the fixture:

codetitle. test/fixtures/robots.yml

one:
  id: 1
  name: Doctor Pneumonic
  power: genius
two:
  id: 2
  name: Maximillian 3000
  power: death ray 

Update the database structure and data

shell> rake db:migrate
shell> rake db:fixtures:load

What does this do? The first line will run our 005_create_robots.rb migration in order to modify the structure of the database. The second line will load robots.yml as the test data in the database.

The controller

Create the files needed for the views and the controller:

$ script/generate controller Robots index show new edit
      exists  app/controllers/
      exists  app/helpers/
      create  app/views/robots
      exists  test/functional/
      create  app/controllers/robots_controller.rb
      create  test/functional/robots_controller_test.rb
      create  app/helpers/robots_helper.rb
      create  app/views/robots/index.rhtml
      create  app/views/robots/show.rhtml
      create  app/views/robots/new.rhtml
      create  app/views/robots/edit.rhtml

action index

def index
  @robots = Robot.find :all
end

In this action, we are using the class method Robot#find to get an array of all the robots in existence. This array is assigned to the variable @robots.

combined code

Here is the combined code for a basic a CRUD controller:

codetitle. app/controllers/robots_controller.rb

class RobotsController < ApplicationController

  def index
    @robots = Robot.find :all
  end
  
  def show
    @robot = Robot.find params[:id]
  end
  
  def new
    @robot = Robot.new
  end
  
  def create
    @robot = Robot.new params[:robot]
    if @robot.save
      redirect_to :action => 'show', :id => @robot.id
    else
      render :action => 'new'
    end
  end
  
  def destroy
    @robot = Robot.find params[:id]
    @robot.destroy
  end
  
  def edit
    @robot = Robot.find params[:id]
  end
  
  def update
    @robot = Robot.find params[:id]
    if @robot.update_attributes(params[:robot])
      redirect_to :action => 'show', :id => @robot.id
    end
  end

end

The views

codetitle. app/views/robots/index.html.erb

<h1>Listing robots</h1>

<table>
  <tr>
  </tr>

<% @robots.each do |robot| %>
  <tr>
    <td><%= link_to robot.name, :action => 'show', :id => robot.id %></td>
    <td><%= link_to 'Edit', :action => 'edit', :id => robot.id %></td>
    <td><%= link_to 'Destroy', {:action => 'destroy', :id => robot.id}, :confirm => 'Are you sure?', :method => :post %></td>
  </tr>
<% end %>
</table>

<br />

<%= link_to 'New robot', :action => 'new' %>

codetitle. app/views/robots/new.html.erb

<h1>New robot</h1>
<%= error_messages_for :robot %>

<% form_for(:robot, @robot, :url => {:action => 'create'}) do |f| %>
  <p>
    Title: <%= f.text_field 'title' %>
  </p>
  <p>
    Body: <%= f.text_area 'body' %>
  </p>
  <p>
    <%= f.submit "Create" %>
  </p>
<% end %>

<%= link_to 'Back', :action => nil %>

codetitle. app/views/robots/show.html.erb

<h1><%=h @robot.title %></h1>

<blockquote>
<%=h @robot.power %>
</blockquote>

<p>Created: <i><%= time_ago_in_words(@robot.created_at) %> ago</i></p>

<%= link_to 'Edit', :action => 'edit', :id => @robot.id %> |
<%= link_to 'Back', :action => nil %>

codetitle. app/views/robots/edit.html.erb

<h1>edit robot <%= @robot.title %></h1>

<% form_for(:robot, @robot, :url => {:action => 'update', :id => @robot.id}) do |f| %>
  <p>
    Title: <%= f.text_field 'title' %>
  </p>
  <p>
    Power: <%= f.text_field 'title' %>
  </p>
  <p>
    Body: <%= f.text_area 'body' %>
  </p>
  <p>
    <%= f.submit "Save" %>
  </p>
<% end %>

Run It!

Start Server

(after -p, put any 4 digit number, not beginning with 0)

$ script/server -p 5678
=> Booting Mongrel (use 'script/server webrick' to force WEBrick)
=> Rails application starting on http://0.0.0.0:5678
=> Call with -d to detach
=> Ctrl-C to shutdown server
** Starting Mongrel listening at 0.0.0.0:5678
** Starting Rails with development environment...
** Rails loaded.
** Loading any Rails specific GemPlugins
** Signals ready.  TERM => stop.  USR2 => restart.  INT => stop (no restart).
** Rails signals registered.  HUP => reload (without restart).  It might not work well.
** Mongrel 1.1.4 available at 0.0.0.0:5678
** Use CTRL-C to stop.

Then go to your web browser and type in giip3.ucsc.edu:{4 digit number}/{controller_name}