Create a Blog Application with Ruby on Rails 7. Second Part: Create a Post Model and a Posts Controller

In this part, we will generate a Post model and a Posts controller and start implementing the relationship between users and posts.

All Parts:

  1.  Create a Blog Application with Ruby on Rails 7. First Part: Create the User Resource
  2. Create a Blog Application with Ruby on Rails 7. Second Part: Create a Post Model and a Posts Controller
  3. Create a Blog Application with Ruby on Rails 7. Third Part: Implement User Authentication
  4. Create a Blog Application with Ruby on Rails 7. Fourth Part: Performing Operations on the Post Resource
  5. Create a Blog Application with Ruby on Rails 7. Fifth Part: Implement Authorization

create a post model

Let's generate a Post model with the user_id as the foreign key. Let's generate in the terminal the migration file:

bin/rails g model Post title:string content:text status:integer user:references

When the user creates a post, it has a draft status. Later, when it's finished, the user will publish it, and its status will change to published. To achieve that, we use enums. In Rails, an enum is an attribute that maps to integers in the database but can be queried by name.

Let's edit our migration file to set the default for the post status:

class CreatePosts < ActiveRecord::Migration[7.0]
  def change
    create_table :posts do |t|
      t.string :title
      t.text :content
      t.integer :status, default: 0
      t.references :user, null: false, foreign_key: true
      t.timestamps
    end
  end
end

Finally, we run this migration:

bin/rails db:migrate

 Let's define the post statuses in the post.rb in the app/models/ folder:

enum status: {draft: 0, published: 1}

And in user.rb file we add the has_many association:

has_many :posts

The corresponding belongs_to association was automatically added when we generated the Post model.

create a posts controller

Now, let's generate the Posts controller. In the terminal, we type:

bin/rails g controller Posts

Before we add methods to our controller, let's use the default resource routing to declare the routes to all the actions we'll define for the Post resource. Using the default resource routing, we can declare all the necessary routes for the index, show, new, edit, create, update, and destroy actions. Let's open the config/routes.rb file and add these routes:

resources :posts

Let's now start defining these methods in the Posts controller.

The first method we'll define is the index method.

Usually, a blog application orders posts by the creation date, so let's do that. Let's first add a method in the post.rb file in the app/models/ folder to sort the posts:

def self.by_date
  order('created_at DESC')
end

Then, let's add the index method in the Posts controller and make use of the by_date method:

def index
  @posts = Post.all.by_date
end

In the index view, we will show all posts from all authors. Let's create the index.html.erb template in the app/views/posts/ folder and add the following code:

<p style="color: green"><%= notice %></p>
<h1>Latest Posts</h1>
<ul>
  <% @posts.each do |post| %>
    <li><%= link_to post.title, post_path(post) %></li>
  <% end %>
</ul>

Let's set the root route of our application to this index action. In the config/routes.rb file, let's put this at the top:

root 'posts#index'

Next, we will define the show method, which displays the details of a single post:

 def show
   @post = Post.find(params[:id])
 end

Next, we'll create the corresponding view, show.html.erb, in the app/views/posts/ folder. 

Here, we will show the title of the post, its content, the author, its status, when it was published, and when it was updated:

<p style="color: green"><%= notice %></p>
<article>
  <header>
    <h1><%= @post.title %></h1>
    <p>by <%= link_to @post.user.name, user_path(@post.user)%></p>
    <p><%= @post.created_at %></p>
    <p>Status: <%= @post.status %></p>
    </header>
  <p><%= @post.content%></p>
  <footer>
    <p>Last updated on <%= @post.updated_at %></p>
  </footer>
</article>
<p>
  <%= link_to "All posts", root_path %>
</p>

Post last updated on Dec 17, 2023