某スクールにおいて、チーム開発で、フリーマーケットアプリを作成中であり、使用した技術について公開しています。
※初学者のため、ミスや認識違いが多々あると思いますがご了承ください。
商品詳細ページにコメント機能を実装しました。
全部で7回に分けて記事を投稿しています。
|内容 | url |
|:-----------------|------------------:|:-----------------------------:|
| 第1回 | モデル、マイグレーション編 | https://qiita.com/sho_U/items/03108801146e65d58413 |
| 第2回 | ルーティング編 | https://qiita.com/sho_U/items/5c829b3060be2cce919a |
| 第3回|コントローラー編|https://qiita.com/sho_U/items/8528f336cf0d470cd719|
|第4.1回|ヴュー編(一覧表示)|https://qiita.com/sho_U/items/6190562270c722956547|
|第4.2回|ヴュー編(インプットフォーム)|https://qiita.com/sho_U/items/67c2ede4fc6c605283e2|
|第5回|jquery編|https://qiita.com/sho_U/items/d72b60114f76380d05f6|
|第6回|ajax編|https://qiita.com/sho_U/items/caed9b1471e63d43dd3a|
〜コード全文〜https://qiita.com/sho_U/items/310ac5b653bdfcb99a2c
#ルーティングについて
##必要なルーティングについて
ルーティングを作成するにあたり、遷移先、つまりコントローラーのアクションはどういった物が必要そうか検討しました。
1.comments#create(createアクション)
投稿フォームから、コメントを送信するためのアクション
※ちなみに、商品詳細ページが、コメント投稿画面を兼ねており、(item#showで @comment = Comment.new を定義しているためnewアクションは不要。@comment = Comment.newを定義する理由は、空の@commentを作成し、form_withの遷移先を自動で判別させるため)
2.comments#update(updateアクション)
コメントを仮削除するためのアクション。なぜ、削除なのにcreateなのかといいますと、本アプリは仕様上、1回目のコメント削除は、仮削除と言う形で、削除せずデーターベースに保存しておき、復元できるようにしています。よって、本来の意味は削除ではなく、仮削除状態へ更新するという動作になります。(ビュー上は、以下のように表示するようにしています。)
3.comment#restore(restoreアクション)
仮削除したコメントを復元させるためのアクション。
4.comment#destroy(destroyアクション)
仮削除したコメントを完全に削除するためのアクション。
以上の4つのアクションに遷移するための、ルーティングを作成する必要がありそうです。
##update,destroyに対するルーティング
では、必要なルーティングが洗い出せたところで、それぞれどのように記載するか検討します。
resotore以外の、create,destroy,updataは、Railsで基本となる7つのアクションに含まれるため、まずはそちらから検討します。
シンプルにresouresで作成した場合のルーティングは以下の通りです。
resources :comments, only:[:create,:update,:destroy]
resourcesから生成されたルーティングで、対応可能か検討します。
ルーティングを作成する上で、考慮しなければいけない事は、コントローラーの各アクションへ遷移する際にpathからparamsとしてデーターを送信する必要があるか、ということです。
上記の、pathを比較するとcreate以外は、末尾に/:idが付与されているのがわかると思います。例えば、updateアクションは、”/commnets/:id"となっており、実際のURLは、 "(略)/commnets/5" のように:idの部分に、文字列が記載されます。
この場合は、アクションに対し、paramsというハッシュに、キーはid,バリューは"5"を格納し、
params = {id: "5"}
という形式で送信されます。
受け取ったアクションでは、
pramas[:id]
=> "5"
で、送られてきたバリューを取得することができます。
では、なぜこのような値の受け渡しが必要なのでしょうか。
「create」と、「update,destroy」の両者の違いは、createは無からコメントを作成するのに対し、update,destroyは、現に存在するコメントに対して、行うアクションであるということです。
言い換えると、アクションを行う対象のコメントを特定するための、何らかの情報が必要ということです。この役割を、pathに記載された:idの部分が担うわけです。
paramsを使用しなければ、例えばビュー画面で
このような、入力フォームを設ける事によって、強引に情報を送ってしまう事は可能であるとは思います。が、ユーザービリティは格段に落ちると思います。
しかし、例えば削除ボタンのlinkタグを以下のように記載すると(@commentには、id:5のコメントのインスタンスが格納されているとします)
= link_to '削除する', "/comments/#{@comment.id}" ,method: :patch
# わかりやすさのためprefixは使用していません。
リンクボタンをクリックした段階で、自動的に対象コメントのidである ”5” がコントローラーに送信されるわけです。
こっちの方が、ユーザーにとっても親切です。
ということで、update,destroyについてはresouresによって作成されるルーティングを使用することで実装できそうです。
createに対するルーティング
では、次にcreateに対するルーティングについて検討したいと思います。
createは先ほども説明した通り、対象となるコメントは必要ありません。
では、上記のように、" /comments "というpathで良いでしょうか?
ここで、第1回の記事を振り返ります。
https://qiita.com/sho_U/items/03108801146e65d58413
class CreateComments < ActiveRecord::Migration[5.0]
def change
create_table :comments do |t|
t.references :item, null: false, foreign_key: true
t.references :user, null: false, foreign_key: true
t.integer :delete_check,default: 0
t.string :comment
t.timestamps
end
end
end
Commentモデルのマイグレーションは上記のようになっていました。
これを、データーベース上で表すと
このようなレコード構造となります。
これらの、カラムのうち「id」 「created_at」 「updated_at」 については、コメント作成時に自動で作成されて格納されます。
「delete_check」については、コメント作成時は、"0"が格納されるようにマイグレーションに定義しています。
「usrer_id」 は、コメント作成者のidが格納されるのですが、これは、コントローラー側で、deviseの機能により現在のログインユーザーのidを格納することが可能です。(コントローラー編で説明)
「comment」(注:commentsテーブルのcommentカラムという意味です。ややこしくてすみません)については、フォームに入力された内容がparamsとして、コントローラーのcreateアクションに受け渡されます。
残る「item_id」カラム、これはコメントと商品を結び付けて、どの商品に対するコメントなのかを特定するためののカラムなのですが、フォームには、コメント内容しか入力する欄がありません。そこで、何とかして、item_idをコントローラーにparamsとして送り届ける必要があります。
つまり、createはupdate,destroyと違い、どのコメントに対してかという情報は必要ありませんが、代わりに、どの商品に対してかとう情報をコントローラーに送る必要があるのですね。
update,destroyと同じように、pathに情報を組み込んで、送るという手法を用いようとしたら現在の
/comments
では不可能ですね。
そこでpathに**:id** が付与されるように、ルーティングの記載を変える必要があります。
そこで、ルーティングのネストという手法を用います。
今itemsコントローラーに対するルーティングが以下のように記載されているとします。
resources :items
このルーティングに対し、入れ子構造でcommentのルーティングを記載します。
resources :items do
resources :comments,only[:create]
end
すると、以下のようなpathが生成されます。
/items/:item_id/comments
これで、 :item_id のところにitemのid情報を埋め込むことにより、params = {item_id: "値" } というハッシュで対象商品を特定するための情報を送れそうです。
これに、update,destroyを加えて
resources :items do
resources :comments,only: [:create,:update,:destroy]
end
このように記載することにより、目的は達成されそうです。、、、といいたいところですが、今回は別の方法を採用することにしました。
見てもらったらわかる通り、update,destroyに遷移するためのpathが不必要に長くなっているんですね。この2つは、どのコメントかを特定すればいいだけなので、さらにそのコメントが**どの商品に対するものかという情報(/items/:item_id/の部分)**は不要です。無駄に冗長的にすることで、バグの発生リスクや、見通しが悪くなる可能性が生じます。commentsのresourcesをネストするものと、ネストしないものに分けるといった方法もありそうですが、結果として今回は、
resources :items do
resources :comments, only:[:create,:update,:destroy] do
という形でネストせずに組みました。当然、先ほど説明したとおり、createに対し生成されるpathは、
/comments
となりURLに情報を埋め込むことはできなさそうです。
どのようにして、paramsとして、itemのidを送ったのかは、第4.2回の記事で紹介いたします。
restoreに対するルーティング
では、最後にrestore対するルーティングについて検討したいと思います。
restoreについては、railsの基本アクションではなく、resouresでは作成できないため手動で作成する必要があります。
また、コメントを復元する動作ももupdate,destroyと同じく、対象となるコメントを特定する必要があります。
そのため、
/comments/:id/restore
というpathを生成する必要があります。そこで、下記のようにcommentsのルーティングにネストさせることにしました。
手動でルーティングを作成するときには、ネストする際に member do で入れ子にすることにより、:idが付与されます。
resources :comments, only:[:create,:update,:destroy] do
member do
get 'restore'
end
end
復元といっても、何かしらデーターを送信するわけではなくデーターベースにある情報を元に表示するだけなので、httpメソッドは**「get」**にしました。
目的のpathが生成されていました。
ちなみにネストの方法はmember doの他にcollection doという方法もあり、後者の場合は、:idが付与されません。
resources :comments, only:[:create,:update,:destroy] do
collection do
get 'restore'
end
end
次回(第3回)は、コントローラー編となります。