RoR CRUD Operations

CRUD stands for Create, Read, Update, and Delete. These four operations cover every interaction an application has with its data. Every web application — from a simple blog to a complex marketplace — builds on CRUD. Rails makes all four operations straightforward with ActiveRecord and resourceful routes.

The CRUD Cycle Visualized

              CREATE
              (Add new data)
                  |
                  v
DELETE <----  DATABASE  ----> READ
(Remove data)    |         (View data)
                  |
                  v
              UPDATE
              (Change existing data)

Setting Up a Full CRUD Resource

Use scaffolding to generate a complete CRUD setup instantly:

rails generate scaffold Post title:string body:text published:boolean
rails db:migrate

Scaffolding creates the model, migration, controller with all seven actions, views for each action, and routes — all in one command.

Create — Adding New Records

Creating a record involves two steps: showing a form (new action) and saving the data (create action).

# Controller
def new
  @post = Post.new   ← blank object for the form
end

def create
  @post = Post.new(post_params)
  if @post.save
    redirect_to @post, notice: "Post created!"
  else
    render :new, status: :unprocessable_entity
  end
end
# View: app/views/posts/new.html.erb
<h1>New Post</h1>
<%= form_with model: @post do |f| %>
  <p>
    <%= f.label :title %>
    <%= f.text_field :title %>
  </p>
  <p>
    <%= f.label :body %>
    <%= f.text_area :body %>
  </p>
  <%= f.submit "Publish Post" %>
<% end %>

Read — Displaying Records

Read has two variations: list all records (index) and show one record (show).

# Controller
def index
  @posts = Post.all.order(created_at: :desc)
end

def show
  @post = Post.find(params[:id])
end
# View: app/views/posts/index.html.erb
<h1>All Posts</h1>
<% @posts.each do |post| %>
  <div>
    <h2><%= post.title %></h2>
    <p><%= post.body.truncate(100) %></p>
    <%= link_to "Read More", post_path(post) %>
  </div>
<% end %>
# View: app/views/posts/show.html.erb
<h1><%= @post.title %></h1>
<p><%= @post.body %></p>
<p>Published: <%= @post.published? ? "Yes" : "No" %></p>
<%= link_to "Edit", edit_post_path(@post) %>

Update — Changing Existing Records

Updating also involves two steps: showing the edit form (edit action) and saving the changes (update action).

# Controller
def edit
  @post = Post.find(params[:id])
end

def update
  @post = Post.find(params[:id])
  if @post.update(post_params)
    redirect_to @post, notice: "Post updated!"
  else
    render :edit, status: :unprocessable_entity
  end
end
# View: app/views/posts/edit.html.erb
<h1>Edit Post</h1>
<%= form_with model: @post do |f| %>
  <p>
    <%= f.label :title %>
    <%= f.text_field :title %>
  </p>
  <p>
    <%= f.label :body %>
    <%= f.text_area :body %>
  </p>
  <%= f.submit "Save Changes" %>
<% end %>

Delete — Removing Records

# Controller
def destroy
  @post = Post.find(params[:id])
  @post.destroy
  redirect_to posts_path, notice: "Post deleted."
end
# View link to delete
<%= button_to "Delete", post_path(@post), method: :delete,
    data: { confirm: "Are you sure?" } %>

CRUD ↔ HTTP Verb ↔ URL Mapping

Operation  HTTP Verb  URL               Controller#Action
-----------------------------------------------------------
Create     GET        /posts/new        posts#new
           POST       /posts            posts#create
Read       GET        /posts            posts#index
           GET        /posts/:id        posts#show
Update     GET        /posts/:id/edit   posts#edit
           PATCH      /posts/:id        posts#update
Delete     DELETE     /posts/:id        posts#destroy

Strong Parameters — Required for Create and Update

private

def post_params
  params.require(:post).permit(:title, :body, :published)
end

This private method filters the form data. Only the listed fields reach the database. Any other field a user attempts to inject gets silently ignored.

Bulk Operations

ActiveRecord supports operating on multiple records at once:

# Update all drafts to published
Post.where(published: false).update_all(published: true)

# Delete all posts older than one year
Post.where("created_at < ?", 1.year.ago).destroy_all

# Create multiple records at once
Post.insert_all([
  { title: "Post 1", body: "Body 1" },
  { title: "Post 2", body: "Body 2" }
])

The save vs create Difference

MethodWhat It DoesReturns on Failure
saveSaves existing object to databasefalse
save!Same but raises an error on failureRaises ActiveRecord::RecordInvalid
createBuilds and saves in one stepObject with errors (not saved)
create!Same but raises an error on failureRaises ActiveRecord::RecordInvalid

Use the bang version (!) in scripts or seeds where you want the program to stop immediately if something goes wrong. Use the non-bang version in controllers where you want to handle failures gracefully and show the user an error message.

CRUD is the backbone of data-driven applications. Every feature you build in Rails comes back to one or more of these four operations working together.

Leave a Comment

Your email address will not be published. Required fields are marked *