モデルに独自のバリデーションを書かずにコントローラー内で処理をする方法を考えてみました。
環境
ruby 2.6.5 rails 5.2 Mac OS必要な gem 無し
テーブルは
Post : comment が 1対多になってます。
実装したいこと
userの投稿にたとえばコメントがあったとして、そのコメント数を制限する。 みたいな感じの機能です。大雑把な流れとして
userが投稿詳細ページからコメントを追加
↓
createアクションが動く
↓
投稿に対するコメント数が条件より少ない場合、そのまま作成され
条件を超えた場合はflashと共に元のページにリダイレクトさせる
何を使うか
コメントのカラムには自身が持つ"id"の他に外部キーとして"post_id"を持たせています。 これによって「post_idがn番のコメント」と表現することができます。 今回数えたいのはまさにこのpost_idです。情報を取得するメソッドはたくさんあるのでそのなかから最適なものを探します。
- all
- find または find_by
- select
- where
くらいでしょうか。
allはモデルの情報全て持ってくるし、findはidのレコード持ってくるだけだし、find_byも同じく使わないし、selectは指定したカラムの情報を全て返すし、みたいな感じでいろいろ試していったところ
「where」が1番適していました。
ALL:
@posts = Post.all
インスタンス = モデル名
FIND:
@post = Post.find(id)
#引数には必要なレコードのidを指定
FIND_BY:
@post = Post.find_by(email: params[:email]) ←他にも指定できます。
#カラムと実際の値を記載する
SELECT:
@comment = Post.select(:post_id)
#カラムを指定
WHERE:
@comments = Post.where(post_id: params[:post_id])
#カラムと実際の値を記載
みてわかる通り、find_byは1件のレコードを返すのに対して、whereは指定された値のカラムを全て返します。
Commentモデル内に10個くらいデータがあったとして、そのうちpost_idが"3"のものがいくつあるか知りたい場合は
@comments = Comment.where(post_id: 3)
とすることでpost_idが3のものが帰ってきます。
注意としてはここで返ってきた情報に対して、他のカラムを参照したりすることはできないです。
あくまでpost_idが3のものを表示しているだけなので
、
findやfind_byなどはidに対応するレコードを持ってくるので
@user = User.find(1)
@user.id
@user.nickname
@user.age
こう書いてカラムを呼び出すことができます。
実装
さっき書いたcomments = Comment.where(post_id: post_id)
これをコントローラーのcreateアクションに書いて
def create
@comment = Comment.new(comment_params)
comments = Comment.where(post_id: params[:post_id])
if comments.count < 10
if @comment.save?
flash[:notice] = "成功しました"
redirect_to root_path
else
flash[:alert] = "失敗しました"
redirect_to post_path(@post)
end
else
flash[:alert] = "これ以上追加できません"
redirect_to post_path(@post)
end
end
こんな感じで10件まで追加できるようになりました!