Rails の new, create アクションを理解しよう
学習の目標
本章では、以下の内容を学習します。
- new アクションの役割と動作原理を理解する
- create アクションの処理フローを学ぶ
- フォームの作成と送信の仕組みを理解する
- form_with ヘルパーの基本的な使い方を習得する
- リダイレクトと render の違いと使い分けを理解する
はじめに
前回は index, show アクションについて学びました。今回のレクチャーでは、新規データ作成に関わる new アクションと、create アクションについて詳しく解説していきます。
これらのアクションは、Webアプリケーションでユーザーからの入力を受け付け、データベースに保存するという重要な役割を担っています。フォームの仕組みと合わせて理解していきましょう。
newアクション - 新規作成用の空オブジェクトを用意
newアクションの役割
new アクションでは、新規投稿用の「空のモデルオブジェクト」を生成します。コード例は、次のようになります。
def new
@post = Post.new
end
このシンプルなコードで、新しい空の Post オブジェクトを作成し、@post というインスタンス変数に格納しています。この時点では、データベースには何も保存されていません。
ここで生成された @post
をフォーム画面 new.html.erb
に渡すことで、フォーム部品に値を入れやすい形を作っています。
フォームビューの書き換え
投稿フォームでは form_with という重要なヘルパーメソッドを使います。scaffoldで作られた書き方がありますが、理解しやすい内容に書き換えてみましょう。
new.html.erb
を開き、以下のように書き換えてください。
<h1>New post</h1>
<%= form_with(model: @post) do |form| %>
<div>
<%= form.label :title, style: "display: block" %>
<%= form.text_field :title %>
</div>
<div>
<%= form.label :body, style: "display: block" %>
<%= form.text_area :body %>
</div>
<div>
<%= form.submit %>
</div>
<% end %>
<br>
<div>
<%= link_to "Back to posts", posts_path %>
</div>
ここで、form_with という見慣れないヘルパーメソッド(Rails独自の書き方)が出てきました。この点について、詳しく見ていきましょう。
form_with の使い方とフォームの基本
form_with とは
Railsでは、フォームを作成する際に form_with というヘルパーメソッドを使います。これを使うと、データの送信先(どのアクションに送るか)や、どのモデルのデータを扱うかを簡単に指定できます。
フォームのコードの1行目に注目してみましょう。
<%= form_with(model: @post) do |form| %>
ここでは model: @post
と書いているので、このフォームは @post
(Postモデルのオブジェクト)に関連付けられます。新規作成時は create アクション、編集時は update アクションへ送信されるフォームになります。
form_with に渡すモデルが、newアクションで作成された新しいオブジェクトであれば、フォームは新規作成用のフォームになります。一方、editアクションで取得した既存の投稿データが入ったオブジェクトであれば、フォームは編集用のフォームになります。
このような特徴を持っているため、実は newアクションと editアクションで同じフォームを使うことができるのです。Railsがモデルの状態を見て、適切な動作を自動的に決定してくれます。
ブロック変数 form とは?
do |form|
の部分は「ブロック」です。ブロック変数の名前は自由ですが、多くの場合 form や f と書かれることが多いです。
この form はフォーム全体を表すオブジェクトで、フォーム内の各パーツを生成するためのヘルパーメソッドを呼び出す役割を持ちます。
フォーム部品の作成
<%= form.label :title, style: "display: block" %>
<%= form.text_field :title %>
<%= form.text_area :body %>
form.label :title
は入力欄のラベル(見出し)を作ります。form.text_field :title
は1行のテキスト入力欄を作ります(タイトルなど短い文字列の入力に向いています)。form.text_area :body
は複数行のテキスト入力欄を作ります(本文など長文の入力に向いています)。
フォーム送信ボタン
<%= form.submit %>
これはフォームの送信ボタンを生成するためのヘルパーメソッドです。デフォルトのボタンラベルは「Create Post」ですが、次のように書けばボタンのラベルを変えられます。
<%= form.submit "投稿する" %>
createアクション - データベースへの保存を実行
createアクションの役割
create アクションでは、実際にモデルにデータを保存する処理を行います。フォームから送信されたパラメータ(params[:post]
)をもとに、Post.new
でインスタンスを作成し、@post.save
によってデータベースに書き込みます。
def create
@post = Post.new(post_params)
if @post.save
redirect_to post_path(@post), notice: "Post was successfully created."
else
render :new
end
end
# ...略
private
def post_params
params.require(:post).permit(:title, :body)
end
post_params
はストロングパラメータと呼ばれる仕組みで、セキュリティのためにtitleとbodyだけを受け取るように制限しています。これにより、悪意ある送信から守ることができます。
また、@post.save
という部分では、作成された @post
、つまり投稿データをデータベースに保存しています。
保存に成功した場合
保存に成功したら @post.save
の結果は true になるので、if文の最初のブロックに入り、以下の1行が実行されます。
redirect_to post_path(@post), notice: "Post was successfully created."
まず、redirect_to post_path(@post)
という部分は詳細画面(showアクション)に移動させる、という意味になります。別ページへ移動させることは「リダイレクト」と呼ばれます。
この記述は「お決まりの書き方」として覚えていただいてOKです。今回、コントローラは posts_controller
という名前でしたね。その「posts」という部分が鍵になっています。
showアクションは「複数」ではなく「単体」の投稿データに関するページなので「s」を外した「post」という名前をまず使っています。そしてRailsでは、そういった単体の投稿へのページを表す道筋、つまりパスを「post_path」と表記したメソッドを使います。
投稿の詳細ページを開く対象となる投稿データをどれか一つ指定しなければならないので、post_path
に対して、対象となる投稿データである @post
を引数として渡しています。
このように、とあるページへの道作り(ルーティング)を助けてくれるようなメソッドをヘルパーメソッドと呼びます。他にもありますが、まずはこういったルーティングに関するヘルパーメソッドから覚えておきましょう。
また、リダイレクトさせた後、投稿に成功した旨を表示するための記述がこの部分です。
notice: "Post was successfully created."
これは、app/views/posts/show.html.erb
における以下の部分で使われます。scaffoldで作った場合、この記述が自動で追加されているはずです。
<p style="color: green"><%= notice %></p>
コントローラで notice という変数が作られ、メッセージを埋め込み、そのメッセージをビューで表示するといった流れになっています。ただし、リロードすると消えるかと思います。
このように、一時的に表示させるためのメッセージをフラッシュメッセージと呼びますので、覚えておきましょう。こういった一時的な表示のされ方はRailsが裏側でうまいことやってくれているためですので、「こういうもの」と覚えてしまって大丈夫です。
保存に失敗した場合
@post.save
という記述では入力データをもとに投稿データを保存していますが、これに失敗した場合はどうなるでしょうか?
まず、@post.save
の結果は false となります。そして createアクションでは if @post.save
と書いてあるので、else文の処理が実行されることになります。
render :new
データ保存成功時は redirect_to
と書いていましたが、今回は render
となっていますね。これらの違いは以下のようになります。
- redirect_to:リダイレクト先のページを開くためのアクションを実行する
- render :xxx:別なアクションは呼び出さずに xxx.html.erb を開く
結果的に開かれるページは同じビュー(xxx.html.erb)を使っているわけなのですが、render
が redirect_to
と大きく違うのは、ビューに対応するアクションを呼び出さないという点です。
createアクションでは render
メソッドで new.html.erb
をそのまま開いているので、データベースに保存、つまり save しようとしていた @post
はそのまま使いまわされます。その @post
を new.html.erb
で表示すると、入力していた文字などをそのまま表示することができます。
一方、redirect_to
メソッドを使って newアクションを呼び出すことで newのビューを表示してしまうと、newアクションにより @post
が初期化されてしまうので、まっさらになってしまいます。
例えばこれが氏名・住所・プロフィールなどを一気に記入するようなフォームだとしたら、ゼロから入力するのは面倒ですよね。そのため、newアクションをゼロから実行する redirect_to
ではなく、@post
を使い回してビューを表示できる render
というメソッドを使っているのです。
データの流れを理解する
ここで、newアクションからcreateアクションまでの一連の流れをおさらいしておきましょう。
- ユーザーが「New Post」リンクをクリックする → newアクションが実行される
- newアクションでは
@post = Post.new
で空の投稿オブジェクトを作成 new.html.erb
でform_with(model: @post)
を使ってフォームを表示- ユーザーがフォームに入力し、送信ボタンをクリック
- フォームのデータが createアクションに送信される
- createアクションでは
@post = Post.new(post_params)
でモデルオブジェクトを作成 @post.save
でデータベースに保存を試みる- 保存に成功したら、
redirect_to post_path(@post)
で詳細ページにリダイレクト - 保存に失敗したら、
render :new
でフォームを再表示
データを作成するという基本的な機能でも、さまざまな処理が行われていることがわかります。特に、redirect_to
と render
の使い分けは重要ですので、しっかりと理解しておきましょう。
この流れはカリキュラムの中でも何度も出てくる内容ですので、しっかりと覚えておいてください。
まとめ
本章では、Railsにおけるnew, createアクションの役割と動作原理について学びました。
- newアクションは、新規データ作成用の空のモデルオブジェクトを生成する
- createアクションは、フォームから送信されたデータをもとに実際にデータベースに保存する
- form_withは、フォームを簡単に作成するためのRails独自のヘルパーメソッド
- redirect_toとrenderの違いは、アクションを再実行するかしないかの違い
- 保存失敗時にrenderを使うことで、入力内容を保持したままフォームを再表示できる
これらの概念を理解することで、ユーザーからの入力を受け取り、データベースに保存するという基本的な処理の流れがわかります。次の章では、edit, updateアクションについて学んでいきましょう。