form_withは重要なパートですね。
まず下処理として、以下の記述
・
・
・
def new
@user = User.new
end
view側で以下を記述
<h1>Sign up</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_with(model: @user, local: true) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.email_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Create my account", class: "btn btn-primary" %>
<% end %>
</div>
</div>
これらを分解して理解していくと、
まず以下の部分ですが、
form_withはデフォルトで“remote” XHR requestを送るため、local: trueと設定することで同期通信とする。
以前、非同期通信の実装でデフォルトがremoteとなっていることを知らず、つまづいたので忘れないようメモ。
<%= form_with(model: @user, local: true) do |f| %>
.
.
.
<% end %>
そして、f.formなどありますが、これらをhtmlでみてみると以下の通りです。
<form accept-charset="UTF-8" action="/users" class="new_user"
id="new_user" method="post">
<input name="authenticity_token" type="hidden"
value="NNb6+J/j46LcrgYUC60wQ2titMuJQ5lLqyAbnbAUkdo=" />
<label for="user_name">Name</label>
<input id="user_name" name="user[name]" type="text" />
<label for="user_email">Email</label>
<input id="user_email" name="user[email]" type="email" />
<label for="user_password">Password</label>
<input id="user_password" name="user[password]"
type="password" />
<label for="user_password_confirmation">Confirmation</label>
<input id="user_password_confirmation"
name="user[password_confirmation]" type="password" />
<input class="btn btn-primary" name="commit" type="submit"
value="Create my account" />
</form>
例えば、以下のコードは
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.email_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<label for="user_name">Name</label>
<input id="user_name" name="user[name]" type="text" />
<label for="user_email">Email</label>
<input id="user_email" name="user[email]" type="email" />
<label for="user_password">Password</label>
<input id="user_password" name="user[password]" type="password" />
例えば、この中の"user[email]"という値は、userハッシュの:emailキーの値(params[:email])と一致します。
@user = User.new(params[:user])
実際にはこのようなコードとほぼ同じである、ということです。
@user = User.new(name: "Foo Bar", email: "foo@invalid",
password: "foo", password_confirmation: "bar")
また、このような記述がありました。
要は、railsが自分のクラスや@userの中身を踏まえて、メソッドを決定してくれるとのことです。賢いですね。
つまり、@userがnewアクションでは空なので、updateアクションを実行してくれます。賢いですね。(2回目)
したがって、htmlの記述は以下の通りです。
action="/users"とポストメソッドでnewアクションが実行されるというわけですね。
<form action="/users" class="new_user" id="new_user" method="post">
そして、POSTリクエストはcreateアクションに送られます。ここで、createアクションでフォーム送信を受け取り、User.newを使って新しいユーザーオブジェクトを作成し、ユーザーを保存(または保存に失敗)します。
なので、newアクションとupdateアクションはセットで必要となります。
これで問題なさそうですが、実は問題があります。
それは以下の書き方にはセキュリティ上の問題があります。
@user = User.new(params[:id])
回避するためには、ストロングパラメーターが必要です。
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
flhashの表示
以下の説明が分かりやすい。
def create
@user = User.new(user_params)
if @user.save
flash[:success] = "Welcome to the Sample App!"
redirect_to @user
else
render 'new'
end
end
<% flash.each do |message_type, message| %>
<div class="alert alert-<%= message_type %>"><%= message %></div>
<% end %>
適用するCSSクラスをメッセージの種類によって変更するようにしています。これにより、例えば:successキーのメッセージが表示される場合、適用されるCSSクラスは次のようになります。
alert-<%= message_type %>
alert-success
このとき、:successキーはシンボルでしたが、テンプレート内に反映させる際に埋め込みRubyが自動的に"success"という文字列に変換している点に注意してください。この性質を利用することで、キーの内容によって異なったCSSクラスを適用させることができ、メッセージの種類によってスタイルを動的に変更させることができます。例えば、8.1.4ではflash[:danger]を使ってログインに失敗したことを表すメッセージを表示します11 (実際、既にalert-dangerというCSSクラスを使って、リスト 7.21のエラーメッセージのスタイルをdivタグで指定しています)。Bootstrap CSSは、このようなflashのクラス用に4つのスタイルを持っています(success、info、warning、danger)。また、本書のサンプルアプリケーションでは、これらの全てのスタイルを場合に応じて使っていきます(例えば11.2ではinfoを、8.1.4ではdangerを使います)。
テンプレート内にflashのメッセージが差し込まれるので、次のようなコードは、
flash[:success] = "Welcome to the Sample App!"
最終的には次のようなHTMLになります。
<div class="alert alert-success">Welcome to the Sample App!</div>
第7章は、以下の2点を理解できたら大丈夫かなと思います。
・form_withを使って、newアクション、createアクションを実装する
・flashの使い方
gravatorも出てきましたが、ある程度知っていればよさそう。