こんにちは、かつコーチです。
「フォームを送信したのに、エラーが出て保存できない」。
Rails初心者がコントローラを書き始めたときによく経験するつまずきです。
この記事では、コントローラの作り方・アクションの書き方に加えて、初心者がつまずきやすいストロングパラメータの仕組みを解説します。
読み終える頃には、安全にデータを受け取るコントローラを書けるようになります。
コントローラの生成
rails generate controllerコマンド
コントローラは、rails generateコマンド(省略形rails g)を使って生成できます。
bin/rails g controller Posts
このコマンドを実行すると、app/controllers/posts_controller.rbが自動的に作成されます。
コントローラ名は複数形で指定するのが規約です。
前々回の記事で紹介した「設定より規約(CoC)」がここでも活きています。
生成される基本の形
生成直後のコントローラは、次のような空のクラスです。
# app/controllers/posts_controller.rb
class PostsController < ApplicationController
end
ApplicationControllerを継承することで、Railsが用意している便利な機能を使えるようになります。
この中に、これから紹介するアクションを追加していきます。
アクションの書き方
基本の7つのアクション
前回の記事で紹介したresources :postsは、次の7つのアクションを想定して作られています。
| アクション | 役割 |
|---|---|
index | 一覧を表示する |
show | 詳細を表示する |
new | 新規作成画面を表示する |
create | データを新規作成する |
edit | 編集画面を表示する |
update | データを更新する |
destroy | データを削除する |
これらのアクションは、コントローラ内でメソッドとして定義します。
class PostsController < ApplicationController
def index
@posts = Post.all
end
def show
@post = Post.find(params[:id])
end
end
params[:id]は、URLに含まれるIDの値を取得するための書き方です。
たとえば/posts/3にアクセスすると、params[:id]には"3"という値が入ります。
createアクションでデータを保存する
フォームから送信されたデータを保存するには、createアクションを使います。
def create
@post = Post.new(post_params)
if @post.save
redirect_to @post, notice: "投稿を作成しました"
else
render :new, status: :unprocessable_entity
end
end
saveが成功すれば詳細ページへ、失敗すれば新規作成画面を再表示するという分岐です。post_paramsというメソッドがここで登場していますが、これが次に説明するストロングパラメータです。
ストロングパラメータとparams.require
なぜストロングパラメータが必要なのか
フォームから送られてくるデータは、paramsという形でコントローラに渡ってきます。
しかし、paramsをそのままモデルに渡してしまうと、想定していない項目まで一括で保存されてしまう危険があります。
たとえば「管理者権限フラグ」のような項目があった場合、悪意のあるリクエストによって不正に書き換えられてしまう可能性があるのです。
この問題を防ぐための仕組みがストロングパラメータです。
受け取ってよい項目を明示的に指定し、それ以外は受け付けないようにする安全対策です。
params.requireとpermitの書き方
ストロングパラメータは、requireとpermitという2つのメソッドを組み合わせて書きます。
private
def post_params
params.require(:post).permit(:title, :body)
end
params.require(:post)は「postというキーの中身を必須とする」という意味です。.permit(:title, :body)は「titleとbodyという項目だけを受け取ってよい」という意味です。
このメソッドをprivate(外部から呼び出せない領域)に定義し、createやupdateアクションの中から呼び出すのが一般的な書き方です。
つまずきやすい設定・注意点
permitに項目を入れ忘れるとデータが保存されない
permitに指定していない項目は、フォームで入力しても保存時に無視されます。
新しいカラムを追加したのに保存されない、という場合はpermitの指定漏れを疑いましょう。
フォームのname属性とpermitの対応
フォームのinputタグのname属性がpost[title]のような形になっている場合、Railsはこれをparams[:post][:title]として受け取ります。require(:post)の:postは、このフォームの構造と対応させる必要があります。
よくあるつまずきポイント・エラー対処
Before/After:permitを書かずに保存しようとするケース
ストロングパラメータの仕組みを知らずに、paramsをそのままモデルに渡してしまうのは典型的な失敗パターンです。
私が初めてcreateアクションを書いたとき、permitを書かずにparams[:post]をそのまま渡してしまい、次のエラーに遭遇しました。
❌Before:paramsを直接モデルに渡してしまう
def create
@post = Post.new(params[:post]) # ストロングパラメータを使っていない
@post.save
end
このコードを実行すると、次のようなエラーが表示されます。
ActionController::ForbiddenAttributesError
これは「許可されていないパラメータを、そのままモデルに渡そうとしている」というエラーです。
Rails 4以降、セキュリティ対策としてこの仕組みが標準で組み込まれており、permitを通さないデータは受け付けない設計になっています。
✅After:requireとpermitで明示的に許可する
def create
@post = Post.new(post_params)
@post.save
end
private
def post_params
params.require(:post).permit(:title, :body)
end
このようにpost_paramsメソッドを経由させることで、titleとbodyだけが安全に渡されるようになります。
エラーメッセージにForbiddenAttributesErrorと表示されたら、まずストロングパラメータの書き忘れを疑うとよいでしょう。
まとめ
この記事のポイント
- コントローラは
rails g controllerコマンドで生成し、app/controllersに配置する index・show・createなど、目的ごとにアクションをメソッドとして定義する- ストロングパラメータは
params.require(:モデル名).permit(:項目名, ...)という形で書く permitを書き忘れるとForbiddenAttributesErrorが発生し、データを保存できない
次に読むべき記事
コントローラの基本が身についたら、次はユーザーに見せる画面の作り方を学びましょう。
「ビュー(ERB)の基本とレイアウト」で、画面表示の仕組みを確認してみてください。
タグ: Ruby on Rails, 初心者向け, フレームワーク基礎