LoginSignup
0
0

More than 1 year has passed since last update.

【Rails】コントローラの異なるページ上で投稿/削除するしくみをつくる

Last updated at Posted at 2022-09-22

目標物の確認

今回の目標物は以下のようです。
Qiita用.jpg
ユーザーAのポストに対し、ユーザーBがコメントを投稿します。
コメントの投稿フォームはposts/show内にあります。
コメントはposts/show内で表示され、自分のコメントに対しては削除することが可能です。

分からなかったこと

ポスト表示ページのパスがposts/:idであり、ページが持つ固有のparams要素はidのみであるならば、、、

  • コメントを作成する際はCommentモデルのpost_idカラムにparams[:id]を代入すれば良いのは分かる。
  • コメントを削除する時、該当するコメントのidfind_byを使って探すことができない。
    paramsが持つidはPostモデルのidであり、Commentモデルのidではないから。)

解決策

  • モデル同士を紐づけて
  • ルーティングをネストして
  • コントローラを設計し
  • ビューファイルのform_withlink_toにひと手間加える

モデルの紐づけ

PostモデルとCommentモデルに主従関係を持たせます。

Post: 大元の投稿

post.rb
has_many :comments

Comment: postへのコメント

comment.rb
belongs_to :post

ルーティングのネスト

今回のケースのように、あるコントローラ内で別のコントローラを動かすときは、ルーティングをネストさせます。

route.rb
resources :posts do
  # 今回使用するコメント機能は投稿と削除だけ
  resources :comments, only: [:create, :destroy]
end

これにより、どのようなパスが構成されるのか確認しましょう。

$ rails routes

の結果を見ると

posts          GET     /posts(.:format)                         posts#index
post_comments  POST    /posts/:post_id/comments(.:format)       comments#create
post_comment   DELETE  /posts/:post_id/comments/:id(.:format)   comments#destroy

ここでPOSTDELETEのHTTPリクエストに対して:post_id:idがあることに注目します。
post_idはCommentモデルがもつカラム
idはPostモデルがもつカラム
です。
コントローラを設計する際、paramsに何を入れて情報を送るのかを考える際に必要になりますので意識しましょう。

コントローラの設計

コメントの投稿

コメントを作成するアクションはこちらです。

comments_controller
def create
  # 紐づけ先の@postを定義
  @post = Post.find(params[:post_id])
  # @commentは@postに紐づけるのでnewではなくbuild
  @comment = @post.comments.build(comment_params)
  @comment.save
  # リダイレクト先は@commentに紐づいたpost/:id
  redirect_to post_path(@comment.post_id)
end

private
  # comment_paramsはストロングパラメータ
  def comment_params
    params.requier(:comment).permit(:content, :post_id)
    # 必要であればmerge内にuser_id: @current_user.idも追加
  end

コメントの削除

コメントを削除するアクションは以下です

comments_controller.rb
def destroy
  # @commentは:idパラメータから探す
  @comment = Comment.find(params[:id])
  @comment.destroy
  # リダイレクト先は、ひとつ前のページ又はposts/index
  redirect_to request.referrer || posts_path
end

ビューファイル

コメントの投稿

posts/show.html.erb
<%= form_with model: [@post, @comment], local: true do |f| %>0
  <%= f.text_area :content, required: true %>
  <%= f.submit "送信" %>
<% end %>

コメントを投稿する際は、form_withのmodel要素にコントローラのアクションで定義したインスタンス変数を配列として与えます。
これによってRailsはpost_comments_pathというcreateメソッドのパスにパラメータを送信します。

コメントの削除

posts/show.html.erb
# コメントしたユーザーが自分かどうかを確認
<% if @comment.user.id == @current_user.id %>
  # post_comment_pathには2つのidがある
  <%= link_to("削除", post_comment_path(@comment.post_id, @comment.id),
    {method: "delete", data: {confirm: "削除しますか?"}})
  %>
<% end %>

コメントを削除するパスは、rails routesで確認したpost_comment_pathを使用します。
このパスは上で確認した通り/posts/:post_id/comments/:idであり、2つのidをもっています。
:post_idには@comment.post_id
:idには@comment.id
を与えます。

また、削除パスのメソッドは"delete"なので、これも明記する必要があります。
ついでにリンクをクリックするといきなり削除されてしまうのを防ぐため、JavaScriptで削除の確認コメントが出るようにdata要素も追加しました。

以上で、コントローラの異なるページ上で投稿/削除するしくみをつくることができました。

参考

Railsチュートリアル第13章

【Rails基礎】プログラミング初学者がつまずきやすい「ルーティングのネスト」について簡単に解説

【Rails】 form_withの使い方を徹底解説!#ネストをしている時の書き方

Rails link_toにパラメータを渡す

【Rails】link_to でPrefix pathへの複数idの渡し方

0
0
0

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
0
0