Ruby on Railsチュートリアル第6版の第7章のまとめです。
個人的に気になったところ、難しかったところ、わからなかったところを中心にまとめていきます。基本的に自分の理解を助けることと、復習しやすくすることを目的とした記事ですが、今Ruby on Railsチュートリアルをやってる人に役立つ情報があるかもしれません。
僕の学習の順番は、1周目はRailsチュートリアル第4版(Rails5.1)を使い、2周目で第6版を使うという感じになってます。これは1周目が終わったところで第6版のWebテキスト版がリリースされたからです。
ちなみに、2周目は解説動画を購入してやってます。オススメです。
第7章 ユーザー登録
第7章ではユーザー登録機能を追加します。RESTfulに実装してくみたいなので、RESTの理解と同時に進めてくとよさそうです。
7.1 ユーザーを表示する
ユーザーを表示するためのページ作りから始めます。
いつものようにブランチを作って進みましょう。
7.1.1 デバッグとRails環境
まずサイトにデバッグ情報を表示できるようにコードを追加します。これは開発環境だけで表示したいので、if文を使います。
デバッグ情報の表示を整えるためにSassを追加します。
指示通りにやれば大丈夫だと思います。
7.1.2 Usersリソース
RESTの原則に従ってルーティングを書いていきます。これはすごく簡単で、
resources :users
とするだけです。これだけで7つのルーティングが作られます。便利ですね。
でも、覚えるのが大変。覚えないといけないですよね。。。
これでルーティングはOKなので、ビューとアクションを作ります。アクションで出てくる「params[:id]」については、解説動画の方が圧倒的にわかりやすいと思います。
1周目は「そうやって書くのか」くらいの理解でしたが、解説動画を見てその意味がわかった気がしてます。

7.1.3 debuggerメソッド
debuggerメソッドに必要なbyebugというgemはGemfileを書き換えたときに入ってるので、すでに使えるようになってます。
ここで使い方が説明されてますが、1周目ではどういうときに使えばいいのかよくわからず、ここでしか使いませんでした。
debuggerメソッドの使い方についても、解説動画を見るとよくわかります。

7.1.4 Gravatar画像とサイドバー
ユーザー画像を表示するために、Gravatarというサービスを使います。ページの表示を整えて終了です。
演習1ではGravatarのアカウントを作るというのがありますが、面倒なのでやってません。
7.2 ユーザー登録フォーム
ユーザー登録のためのフォームを作ります。
7.2.1 form_withを使用する
Railsチュートリアル第6版ではフォーク作成にform_withを使います。第4版はform_forでした。
Railsチュートリアルでは、
<%= form_with(model: @user, local: true) do |f| %>
という感じでform_withのコードが書かれてますが、モデルの指定でモデル名ではなく、インスタンス変数が指定されてます。
Railsチュートリアルには
form_withの引数で必要となるUserオブジェクトを作成する
Railsチュートリアル第6版 第7章
という感じで、サラッと書かれてます。引数でUserオブジェクトを使うんだなということがここからわかりますが、ちょっと調べてみました。
「【Rails】form_withの使い方を徹底解説!」によると、モデルの指定のところにはモデルクラスのインスタンスを書くとのことです。
Railsチュートリアルのコードで説明すると、
<%= form_with(model: モデルクラスのインスタンス, local: true) do |f| %>
ということになります。
で、実際のHTMLがどうなるかも調べてみました。まず、指示通りにやるとこんな感じです。
<label for="user_name">Name</label>
<input type="text" name="user[name]" id="user_name" />
nameのところだけを取り出してみました。
newアクションのところでインスタンス変数の名前を@user2に変更して、form_withは@userのままだと、
<label for="name">Name</label>
<input type="text" name="name" id="name" />
となりました。
違いは3つですね。他のフィールドの違いも同じでした。
変数:@user / モデル:@user | 変数:@user2 / モデル:@user | |
---|---|---|
label のfor | user_name | name |
inputのname | user[name] | name |
inputのid | user_name | name |
ちなみに、インスタンス変数を@test、form_withのモデル指定を@testとしてみたら、両方@userにしたのと同じになりました。
もう1つ気になったのが、
<%= f.label :name %>
ここです。「:name」以外のものにしたらどうなるんだろうと思って試してみたところ、表示されるラベル名が変わりました。具体的には「:name2」としてら「Name2」と表示されました。
<label for="user_name2">Name2</label>
<input type="text" name="user[name]" id="user_name" />
labelタグのfor属性はフォームの項目と関連づけるものなので、これだとinputタグのid属性と異なる名前になってて、この2つが関連づけられないことになりますね。
ということは、うまく機能しないはずです。
text_fieldを「:test」に書き換えるのも試してみました。
<%= f.label :name %>
<%= f.text_field :test %>
これはこんな感じになりました。
<label for="user_name">Name</label>
<input type="text" name="user[test]" id="user_test" />
なんか動きがわかってきましたね。
labelメソッド(メソッドでいいですよね?)の引数は、labelタグのfor属性とラベル名を指定。ラベル名の頭文字は大文字になる。
ということは、ラベル名を別に設定できるはずですよね。調べてみたところ、第2引数に指定すればいいみたいです。「連日格闘したform_withとの戦いに決着をつけてきた」を参考にしました。
<%= f.label :name, 'ユーザー名' %>
<%= f.text_field :name %>
こうすると、
<label for="user_name">ユーザー名</label>
<input type="text" name="user[name]" id="user_name" />
こうなりました。これで自由にラベル名を設定する方法がわかりました。まとめるとこんな感じだと思います。
- labelメソッドの第1引数はlabelタグのfor属性を指定し、第2引数がない場合は頭文字を大文字にしてラベル名となる。第2引数がある場合は、第2引数がラベル名になる。
- 〇〇_fieldメソッドの引数は、inputタグのname属性とid属性を指定。name属性は「モデル名の小文字[引数]」、id属性は「モデル名の小文字_引数」となる。
ちなみに、シンボルじゃないものを指定してみたら(「name」)、NameErrorが出て「nameなんて変数とかメソッドとかないよ」と言われました。
7.2.2 フォームHTML
フォームのHTMLの解説です。
どのフィールドを使うかで入力時にどうなるかが違うというのが重要なポイントかなと思います。スマホからメールアドレス入力するときに、出てくるキーボードがサービスによって違ったりする理由がここでわかりました。
7.3 ユーザー登録失敗
最初にユーザー登録が失敗した場合を作っていきます。
7.3.1 正しいフォーム
フォームからの情報を受け取ってユーザー登録をするわけですが、そのためのコードを書いていきます。
基本的には指示通りで大丈夫だと思いますが、form_withのところの検証の続きをやってみました。
まず、
<%= f.label :name %>
<%= f.text_field :test %>
で送信してみました。そうすると、デバッグ情報のパラメーターは、
"user"=>{"test"=>"",
"email"=>"",
"password"=>"[FILTERED]",
"password_confirmation"=>"[FILTERED]"}
こんな感じになりました。inputタグのname属性が「user[test]」になってるので、userハッシュのキーがtestになりました。
Railsコンソールでちょっと実験です。
>> user = User.new
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, password_digest: nil>
新しいユーザーを作ってみて、
>> user[:test] = "test"
とやってみると、
ActiveModel::MissingAttributeError (can't write unknown attribute `test`)
と出ました。「testなんて知らない属性に書き込めないよ!」みたいな感じですね。コードが間違ってないかの確認で「test」を「name」に書き換えたらちゃんと動いたので、コードの書き方自体は間違ってないことがわかります。
なので、labelメソッドと〇〇_fieldメソッドはデータベースのカラム名と一致させる必要があるというのが結論のようです。
7.3.2 Strong Parameters
マスアサイメント脆弱性への対応をします。最初のコードだとparamsハッシュのuser全体をそのまま投入することになりますが、それだと本来はフォームから送信できないパラメーターが送信されたときに問題になります。
ということで、許可された属性だけのときに処理が実行されるようにします。
ちなみに、ストロングパラメーターは、
Web上から入力されてきた値を制限することで、不正なパラメータを防ぐ仕組み
ストロングパラメーターについてサクッと解説。
だそうです。
7.3.3 エラーメッセージ
ユーザー登録が失敗したときにエラーメッセージが表示されるようにします。「メールアドレスが入力されていません」みたいなやつですね。
基本的には指示通りでOKです。pluraizeというステキなヘルパーが出てきますが、日本語のアプリケーションを作るのであれば使う機会はなさそうです。
7.3.4 失敗時のテスト
ここまで実装してきたユーザー登録について、テストを書きます。
ここも指示通りで問題ないと思います。
7.4 ユーザー登録成功
次はユーザー登録が成功した場合を作っていきます。
7.4.1 登録フォームの完成
今の状態でもユーザー登録自体はできてるようですが、その後に表示されるページがないので止まってしまいます。
ということで、redirect_toメソッドを使ってユーザーのプロフィールページにリダイレクトさせます。redirect_toの書き方は省略されたもののようです。
Railsチュートリアルでは簡単に書かれてますが、解説動画ではより詳しく説明されてます。

7.4.2 flash
ユーザー登録が成功したら、登録できたという感じのメッセージがあるとわかりやすいですよね。ここではそれを実装します。
flashというハッシュ「のようなもの」を使います。ここでは、
flash[:success] = ~~~
となってますが、別にsuccessじゃなくても平気なようで、試しにsにしてみましたが表示されました。ただ、それだとCSSがちゃんと設定されてないので、文字が表示されるだけですが。

指示通りにコードを書いてflashの完成です。
7.4.3 実際のユーザー登録
データベースをリセットして、フォームからユーザー登録してみます。
コードが間違ってなければうまくいくはずです。
7.4.4 成功時のテスト
失敗したときのテストと同じように、成功したときのテストを書きます。
ここも指示通りで問題ないと思いますが、演習2で出てくるcotent_tagというヘルパーの説明がないので、調べないとただ同じように書くだけになってしまいます。
「Rails tips: ビューの`content_tag`のあまり知られていないオプション(翻訳)」によると、content_tagはHTMLコードを生成するためのヘルパーで、第1引数にHTMLの要素、第2引数に要素のコンテンツを書くそうです。クラス名を渡すこともできるようです。
これを知った上で演習2のコードを見れば、何をしてるのかがわかると思います。
7.5 プロのデプロイ
いつも通りにコミット、マージ、とやってくわけですが、ここでは本番環境でのSSL設定、サーバーの設定、データベースの設定をします。
Herokuを使ってて、ドメイン名が「herokuapp.com」の場合(独自ドメインを使ってない場合)は指示通りに設定してくだけです。
まとめ
RESTfulが重要なキーワードですが、まだそれがいまいち理解できてません。
でも、とりあえずユーザー登録までは完成したのでアプリケーションっぽさが強くなってきました。form_withなどはRailsアプリケーションで必ず使うと思うのでしっかりと覚えたいところです。
本番環境のSSL化なども終わり、少しずつ本格的な感じになってきました。それと同時に、独自ドメインを使う場合は苦労しそうだなという気もしてます。
まずは、Railsチュートリアルの範囲を学んでくことが重要なので、地道に進んでこうと思います。
