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
| Method | What It Does | Returns on Failure |
|---|---|---|
save | Saves existing object to database | false |
save! | Same but raises an error on failure | Raises ActiveRecord::RecordInvalid |
create | Builds and saves in one step | Object with errors (not saved) |
create! | Same but raises an error on failure | Raises 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.
