CRUD Operations in Ruby on Rails. Let's Build a Blog App
In Ruby on Rails Feb 22, 2024
Updated on April 29, 2024
In this post, we'll cover CRUD operations in Ruby on Rails. We'll create a simple app and implement CRUD operations using Ruby on Rails 7.1.3 and Ruby 3.3.0. We will use Bootstrap to add some styles to our application.
Set Up the Application
Let's set up our application.
Create a New Application
Let's start by creating a new app. In the terminal, we type:
rails new my_blog --css bootstrap
After the creation of the app, let's change directories into it:
cd my_blog
Create A Post Model
First, we will create a Post
model. Each of our blog posts will have a title and content. To create the
Post
model, we use a Rails generator command. In the terminal, we type:
bin/rails g model Post title:string content:text
This command instructs Rails to generate a new model named Post
with two attributes:
title of type string
and content of type text
.
However, merely generating the model isn't enough to make our application aware of it. We need to update the database
schema to include the new Post
model and its attributes. This is where migrations come into play.
Migrations are Ruby scripts that make changes to the database schema, such as creating or modifying tables. After
generating the model, we run the migration by executing
bin/rails db:migrate
in the terminal. This command tells Rails to apply any pending migrations and update the database accordingly. It's important to review the migration file generated by the Rails generator command before running the migration to ensure it accurately reflects the changes we want to make to the database structure.
Add Validations to the Post Model
Validations in Rails are a way to ensure that data stored in the database meets certain criteria or rules defined by the application. They act as safeguards to maintain data integrity and consistency. By applying validations to model attributes, we can enforce specific conditions or constraints on the data we save to the database.
For example, in our Post
model, we want to ensure that every post created has a title and some content.
Let's do this:
validates :title, presence: true
validates :content, presence: true
Set Up the Home Page
On the home page of our application, we'll have a list of all posts. To do this, we'll first create a
Posts
controller. In the terminal, we type:
bin/rails g controller Posts
The first action we'll add to this controller is the index
action:
def index
@posts = Post.all
end
Here, we get all posts from the database and make them available to the controller.
In the config/routes.rb
, we'll set the root
route to this index
action:
root "posts#index"
By doing so, we instruct the application to use the Posts
controller and the index
action
for rendering the home page.
The last thing to do to set up our home page is to create an index
view. The view is a visual
representation of data in an application. In our index
view, we'll display a list of post titles for now.
Let's create the index.html.erb
file in the app/views/posts/
directory.
After that, we edit this file to display a list of posts:
<div class="container mt-5">
<h1>All Posts</h1>
<ul class="list-unstyled">
<% @posts.each do |post| %>
<li><%= post.title %></li>
<% end %>
</ul>
</div>
Declare The Routes
To allow users to interact with a web application's data, it is necessary to establish routes to different actions.
One way to do this is using the resource routing, the default in Rails. This approach enables us to define all common
routes at once, thus simplifying the process. We declare a resource routing by using the resources method. In
config/routes.rb
, let's add this:
resources :posts, except: :index
Create POsts
Creating a resource is the C in CRUD. In this part of our tutorial, we'll explain how to do this in a typical Rails app. To allow users to add a new post, we must provide them with a form. Using a form, we collect data and save it to the database.
Define new and create actions
The first thing we'll do is to add the new
and create
actions to the Posts
controller. First, we add a new
action:
def new
@post = Post.new
end
A new instance of the Post
model is instantiated and assigned to the @post
instance
variable.
At the bottom of our controller, let's add the private method post_params
which will declare the strong
parameters that will be permitted in the create
action and, later, in the update
action:
private
def post_params
params.require(:post).permit(:title, :content)
end
Strong parameters are used to protect against mass assignment vulnerabilities and ensure that only specified attributes can be modified. Strong parameters help prevent unauthorized or malicious manipulation of data submitted via forms.
Now, we can define the create
action:
def create
@post = Post.new(post_params)
if @post.save
redirect_to root_path
else
render :new, status: :unprocessable_entity
end
end
The action attempts to create a new instance of the Post
model with the parameters permitted by the
post_params
method. If the post is successfully saved to the database, the user is redirected to the
root_path
. If validation errors or other issues are preventing the post from being saved, the user is
re-rendered the new
template to correct any errors.
By convention, the new
action typically corresponds to the presentation of a form while the
create
action handles the form submission and saving of data to the database.
Create the Form
We have defined the new
and create
actions. Now, it's time to write the form. We'll create a
partial since we'll use the same form for creating and updating posts. Add the _form.html.erb
partial in
app/views/posts/
directory. Let's edit this file as follows:
<%= form_with(model: post) do |form| %>
<% if post.errors.any? %>
<div class="text-danger mt-4">
<h2><%= pluralize(post.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% post.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<p class="mt-4">
<%= form.label :title, class: "form-label" %>
<%= form.text_field :title, class: "form-control" %>
</p>
<p class="mt-4">
<%= form.label :content, class: "form-label" %>
<%= form.text_area :content, class: "form-control" %>
</p>
<p class="mt-4">
<%= form.submit class:"btn btn-primary" %>
</p>
<% end %>
The form utilizes Rails' form_with
helper method to generate a form for the Post
model.
The conditional block checks for any validation errors and displays them if present, providing users with feedback on any errors preventing the post from being saved.
Each form field is appropriately labeled and styled using Bootstrap classes (form-label
and form-control)
. The text_field
and text_area
helper methods generate input
fields for the title
and content
attributes of the Post
model, respectively.
Finally, the form includes a submit button styled with Bootstrap classes (btn
btn-primary
)
to submit the form.form
Next, we will create a new
view where we will display our from. In the app/views/posts/
directory, we'll add the new.html.erb
file. Let's edit it like this:
<div class="container mt-5">
<h1>New Post</h1>
<%= render "form", post:@post %>
</div>
And then let's link to the new
action in the index
view. After the posts list, add
this:
<p class="mt-5">
<%= link_to "New Post", new_post_path %>
</p>
Read Data
R in CRUD is the acronym for reading data. In this part of our tutorial, we will discuss reading data in a Ruby on Rails application.
The Read operation in Ruby on Rails involves retrieving and presenting data from the application's database to users. It is the foundation of many user interactions and can take various forms, such as displaying lists of records, showing detailed views, or implementing search functionality. For example, in a blog application, the Read operation would involve displaying a list of blog posts on the homepage and allowing users to view individual posts by clicking on them.
Show A Single Post
Next, we'll create a view that will show a single post.
Create a Show Method
To implement the ability to read a single post, we must first add a show
method to the controller. After
the index
method, let's add this:
def show; end
Then, at the bottom of the controller, we'll add the private method set_post
, whose purpose is to find a
post by its ID:
def set_post
@post = Post.find(params[:id])
end
Then, we'll call this method in a before filter at the top of the controller:
before_action :set_post, except: %i[index new create]
except for the index
, new
, and create
actions, of course.
Create a Show View
Next, we will create a show
view. In the app/views/posts/
directory, let's add the
show.html.erb
file. Let's edit it as follows:
<div class="container mt-5">
<h1 class="text-primary"><%= @post.title %></h1>
<div class="mt-4">
<p>
<span>Published at</span>
<span class="fw-bold"><%= @post.created_at.strftime("%b %d, %Y") %></span>
</p>
<p>
<span>Updated at</span>
<span class="fw-bold"><%= @post.updated_at.strftime("%b %d, %Y") %></span>
</p>
</div>
<div class="mt-5"><%= @post.content %></div>
<p class="mt-5">
<%= link_to "All Posts",root_path %>
</p>
</div>
The show.html.erb
view file is structured within a container and displays the title, publication date,
last updated date, and content of the post. The @post
instance variables are used to access the
attributes of the post being displayed.
The publication date (created_at
) and last updated date (updated_at
) are formatted using the
strftime
method to display them in a more human-readable format.
Additionally, a link back to the list of all posts is included at the bottom of the view, allowing users to navigate
back to the index
page easily.
Since we have the show
view, let's edit the create
action to redirect to the newly created
post instead of the home page. Let's edit the create
action in the controller:
def create
@post = Post.new(post_params)
if @post.save
redirect_to post_path(@post)
else
render :new, status: :unprocessable_entity
end
end
Edit the Index View
Let's add some more info about the posts on the home page. Let's edit the index
view to display more
information about each post, including the publication date and a truncated version of the content:
<div class="container mt-5">
<h1>All Posts</h1>
<ul class="list-unstyled mt-3">
<% @posts.each do |post| %>
<li class="mt-5">
<p class="fs-1"><%= link_to post.title, post_path(post) %></p>
<p>
<span>Published at</span>
<span class="fw-bold"><%= post.created_at.strftime("%b %d, %Y") %></span>
</p>
<div>
<%= post.content.truncate(200) %>
</div>
</li>
<% end %>
</ul>
<p class="mt-5">
<%= link_to "New Post", new_post_path %>
</p>
</div>
The index.html.erb
view file is updated to iterate over each post and display its title, publication
date, and truncated content. The link_to
helper method is used to generate links to the show
view of each post, allowing users to navigate to the full content of each post.
Update Data
U in CRUD is the acronym for updating data. In this part of our tutorial, we will discuss updating data in a Ruby on Rails app.
Define edit and update methods
Let's first add an edit
method after the new
method in the Posts
controller:
def edit; end
And after the create
method, we'll add the update
method:
def update
if @post.update(post_params)
redirect_to post_path
else
render :edit, status: :unprocessable_entity
end
end
The edit
method is added to allow users to access a form for editing a specific post. The method itself
doesn't contain any logic other than rendering the edit
template, which will display the form for editing
the post's attributes.
The update
method is added to handle the form submission for updating a post. It attempts to update the
attributes of the post using the parameters submitted via the form. If the update is successful, the user is
redirected to the show
action of the updated post. If validation errors or other issues are preventing
the post from being updated, the edit
template is rendered again to allow the user to correct any errors.
Create an Edit View
Let's now add an edit
view in the app/views/posts/
directory. Let's edit it to include the
form:
<div class="container mt-5">
<h1>Edit Post</h1>
<%= render "form", post:@post %>
</div>
And now, we can link to the edit
action in the show
view. After the div
containing the post content, we'll add this:
<div class="mt-5 d-flex align-items-center">
<%= link_to "Edit Post", edit_post_path(@post), class:"text-info" %>
</div>
We'll add such a button to the index
view as well after the div with the truncated post
content:
<div class="mt-4 d-flex align-items-center">
<%= link_to "Edit Post", edit_post_path(post), class:"text-info" %>
</div>
Delete Data
D in CRUD
is the acronym for deleting data. In this part of our tutorial, we will
discuss deleting data in a Ruby on Rails app.
First, we'll add a destroy
action to the controller:
def destroy
@post.destroy!
redirect_to root_path
end
The destroy
action is defined to delete the post instance and then redirect users to the
root_path
after successful deletion. The use of the destroy!
method ensures that an
exception is raised if the post cannot be deleted, providing a fail-safe mechanism.
Then, we can link to this action first from the show
view. After the link to the edit
action
add this:
<%= button_to "Delete Post", @post, method: :delete, class: "btn btn-outline-danger ms-4" %>
And the same in the index
view, after the link to the edit
action:
<%= button_to "Delete Post", post, method: :delete, class: "btn btn-outline-danger ms-4" %>
Conclusion
In this tutorial, we explored the fundamental CRUD operations (Create, Read, Update, Delete) in a Ruby on Rails application. We learned how to create, read, update, and delete posts using Rails scaffolding and manual implementation. By following along, you've gained a better understanding of how to build a basic blogging application with full CRUD functionality.