125
122

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Railsでコメント機能をつくってみよう

Last updated at Posted at 2018-09-30

目標

ユーザーは投稿ができ、さらに投稿に対してコメントをすることができるようになる
comment_sample.gif

#どんな設計にするのか
・ユーザー
→投稿できる
→投稿に対してコメントを残すことができる

・投稿
→内容のみ

・コメント
→内容のみ

プロジェクトの作成

$ rails new comment_sample
$ cd comment_sample

投稿機能を作る

モデルの作成

今回は投稿者用のUserモデルと投稿用のPostモデルを作ります

deviseの導入

ログインができるようにdeviseを導入します。
Gemfileに以下を追加してください。

Gemfile
gem 'devise'

deviseを使える環境を整えていきます。

$ bundle install
$ rails g devise:install
$ rails g devise user
$ rails g devise:views

Postモデルの作成

投稿用のPostモデルを作成します。ここには投稿内容contentと、誰が投稿したのかというuser_idが入るようにします。

$ rails g model post content:string user:references
$ rails db:migrate

アソシエーションの確認

今作ったUserモデルとPostモデルは1対多の関係です。
ユーザーそれぞれはたくさんの投稿ができ、投稿それぞれは1人のユーザーによって書かれたものであるというようなイメージです。

####user.rb

app/models/user.rb
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
  has_many :posts, dependent: :destroy
end

has_many :posts の後に今回はdependent: :destroyをつけました。これはpostがuserに依存している。ここでは、もしユーザーがデータベースから削除されてしまった場合にユーザーがした投稿も全て消えるようになります。

####post.rb
モデルの作成時にuser:referencesをつけたのですでにbelongs_to :userが書かれています。

app/models/post.rb
class Post < ApplicationRecord
  belongs_to :user
end

コントローラーの作成

users_controller

ユーザーの一覧ページと詳細ページがあることを考慮して、indexアクションとshowアクションを定義します。

$ rails g controller users index show

posts_controller

投稿も同様にindexアクションとshowアクションを定義します。(createアクションもあるが、ビューが存在しないのでここでは書かない)

$ rails g controller posts index show

#ルーティングの作成
ルーティングを考えていきます。

・投稿の一覧と詳細が見れる
・投稿することができる
・ユーザーの一覧と詳細が見れる
ことから以下のようなルーティングにします。
####routes.rb

config/routes.rb
Rails.application.routes.draw do
  devise_for :users

  resources :users, only: [:index, :show]
  resources :posts, only: [:index, :show, :create]

  root 'posts#index'

end

#コントローラーのアクションの作成

##posts_controller.rb
posts_controllerを以下のように変更しよう。

app/controllers/posts_controller.rb
class PostsController < ApplicationController
  before_action :authenticate_user!, only: [:show, :create]
  def index
    @posts = Post.all
    @post = Post.new
  end

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

  def create
    @post = Post.new(post_params)
    @post.user_id = current_user.id
    if @post.save
      redirect_back(fallback_location: root_path)
    else
      redirect_back(fallback_location: root_path)
    end
  end

  private
  def post_params
    params.require(:post).permit(:content)
  end
end

ログインしていないユーザーはshow, createは実行できないようになりました。
#アクションに対応するビューの作成
次はビューを作っていきます。
####posts/index.html.erb

app/views/posts/index.html.erb
<h1>コメントサンプル</h1>
<% if user_signed_in? %>
  <%= link_to "ログアウト", destroy_user_session_path, :method => :delete %>
  <%= link_to "マイページへ", user_path(current_user.id) %>
  <h2>投稿する</h2>
  <%= form_for @post do |f| %>
    <%= f.text_field :content %>
    <%= f.submit %>
  <% end %>
  <hr>
  <h2>投稿一覧</h2>
  <% @posts.each do |post| %>
    <a href="/users/<%= post.user.id %>"><%= post.user.email %></a>
    <p><a href="/posts/<%= post.id %>"><%= post.content %></a></p>
  <% end %>

<% else %>
  <%= link_to "ユーザー登録", new_user_registration_path %>
  <%= link_to "ログイン", new_user_session_path %>
<% end %>

####posts/show.html.erb

app/views/posts/show.html.erb
<h1>投稿詳細ページ</h1>
<h3><%= @post.user.email %></h3>
<h3><%= @post.content %></h3>
<%= link_to "ホームへ戻る", posts_path %>

####users_controller.rb

app/controllers/users_controller.rb
class UsersController < ApplicationController
  def index
    @users = User.all
  end

  def show
    @user = User.find(params[:id])
  end
end

####users/index.html.erb

app/views/users/index.html.erb
<h1>ユーザー一覧</h1>
<% @users.each do |user| %>
  <a href="/users/<%= user.id %>"><%= user.email %></a>
  <hr>
<% end %>
<%= link_to "ホームへ戻る", posts_path %>

####users/show.html.erb

app/views/users/show.html.erb
<h1>ユーザー詳細ページ</h1>
<h3><%= @user.email %></h3>
<h2>投稿内容</h2>
<% @user.posts.each do |post| %>
  <a href="/posts/<%= post.id %>"><%= post.content %></a>
  <hr>
<% end %>
<%= link_to "ユーザー一覧へ", users_path %>
<%= link_to "ホームへ戻る", posts_path %>

#Commentモデルをつくろう
これからやっとコメント機能を実装していきます。
コメント機能は、誰がどの投稿に対してコメントをしたのかという情報をCommentテーブルというUserテーブルとPostテーブルの中間テーブルに格納していきます。

$ rails g model comment content:string user:references post:references
$ rails db:migrate

##アソシエーションの確認

####user.rb

app/models/user.rb
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
  has_many :posts, dependent: :destroy
  has_many :comments
end

####post.rb

app/models/post.rb
class Post < ApplicationRecord
  belongs_to :user
  has_many :comments
end

#コントローラーの作成
####comments_controller

$ rails g controller comments

#ルーティングの作成
####routes.rb

config/routes.rb
Rails.application.routes.draw do
  devise_for :users
  resources :users, only: [:index, :show]
  resources :posts, only: [:index, :show, :create] do
    resources :comments, only: [:create]
  end

  root 'posts#index'
end

#コントローラーのアクションの作成
####comments_controller.rb

app/controllers/comments_controller.rb
class CommentsController < ApplicationController
  def create
    @comment = Comment.new(comment_params)
    @comment.user_id = current_user.id
    if @comment.save
      redirect_back(fallback_location: root_path)
    else
      redirect_back(fallback_location: root_path)
    end

  end

  private
  def comment_params
    params.require(:comment).permit(:content)
  end
end

####posts_controller.rb

app/controllers/posts_controller.rb
class PostsController < ApplicationController
  before_action :authenticate_user!, only: [:show, :create]
  def index
    @posts = Post.all
    @post = Post.new
  end

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

  def create
    @post = Post.new(post_params)
    @post.user_id = current_user.id
    if @post.save
      redirect_back(fallback_location: root_path)
    else
      redirect_back(fallback_location: root_path)
    end
  end

  private
  def post_params
    params.require(:post).permit(:content)
  end
end

#アクションに対応するビューの変更
####posts/show.html.erb
その投稿に対するコメントの一覧と、コメントができるようになります

app/views/posts/show.html.erb
<h1>投稿詳細ページ</h1>
<h3><%= @post.user.email %></h3>
<h3><%= @post.content %></h3>

<h2>コメント一覧</h2>
<% @comments.each do |c| %>
  <div>
    <a href="/users/<%= @post.user.id %>"><%= c.user.email %></a>
    <%= c.content %>
    <hr>
  </div>
<% end %>

<%= form_for [@post, @comment] do |f| %>
  <%= f.text_field :content %>
  <br>
  <%= f.submit 'コメントする' %>
<% end %>

<%= link_to "ホームへ戻る", posts_path %>

#以上です
これでユーザーが投稿に対してコメントをすることができるようになりました。
デザインなど加えてより見やすくしてください

##ソースコードはこちらから
https://github.com/Toomoya/comment_sample

125
122
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
125
122

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?