Ruby on Rails チュートリアル on Cloud9 の学習録(第8章)
先週、たまたまbayfmでHyadain Stationを聞いてから、ヒャダインにハマっています。この番組は、特定のテーマに従って彼が選曲した曲を流す番組ですが、曲のチョイスと紹介が秀逸です。
ガンダムビルドファイターズの新しいエンディングはヒャダインだったのか(笑)ラジオを聞いていて初めて気づいた。良い歌だと思って聞いたけど全然気づかなかった。
【MV】半パン魂【ヒャダイン】- Hanpan Spirit - Hyadain - YouTube
第8章 サインイン、サインアウト
まずは、コントローラーの作成とテストの作成。
$ rails generate controller Sessions --no-test-framework
$ rails generate integration_test authentication_pages
generate integration_testで生成されたテストページを編集。ここで使われている、"subject { page }"の意味が分からない。
8.1.4確認フォームを送信する
&& は論理積。両方の条件がtrueにならない場合は、falseとなる。
8.2.1[このアカウント設定を保存する]
Ruby標準ライブラリのSecureRandomモジュールにあるurlsafe_base64メソッドを使って、ランダムな16文字のコードを生成する。これを、ウェブアプリのデータベースとユーザーのCookieとして保持して、ログイン時に参照させる仕組み。SSL接続にする事で、傍受の可能性を防ぎつつ、毎回、ログイン後にCookieを再発行することで、成り済ましを防ぐ仕組みを作っている。
この説明で、Subjectの意味が分かった!itが示す主語をsubjectで指定する仕組みなのか。
itsメソッドは、itと似ていますが、itが指すテストのsubject (ここでは@user) そのものではなく、引数として与えられたその属性 (この場合は:remember_token) に対してテストを行うときに使用します。
before_create や priveteについてもここで説明している。
8.2.2正しいsign_inメソッド
Railsは単位換算や時間の計算に強い。
「コラム 8.1cookiesは今から20年後に切れる (20.years.from_now)」
8.2.3現在のユーザー
要素代入 (assignment)についての解説があるが…、全然わからない。
メモ: 今更ながら...defはメソッド。
8.2.4レイアウトリンクを変更する
ややこしいメソッド。"!"が否定で、"current_user.nil?"で「現在のユーザーがnilかどうか確認」しているので、「現在のユーザーがnilではない」場合は真、nilの場合は偽となる。
def signed_in?
!current_user.nil?
end
条件によって、メニューを変化させるための方法はこの辺に記載されている。なお、リンクをクリックするとペロっと出るメニューを使うには、application.jsにbootstrapを追加する必要がある。
8.2.5ユーザー登録と同時にサインインする
むむむ...致命的ではないから先送りにした、サインアップ後の画面テストだが、以下のように"user"を"User"に変更すると、テストをパスするようになった(追記:これだとDBにname methodがあるかどうか確認している?)。すぐ上で定義している"let(:user)" から取得しているから、小文字で良いような気がするんだけどなぁ…。
×:it { should have_title(user.name) }
○:it { should have_title(User.name) }
追記:なおった。"fill_in"している部分と、"let(:user)"で取得しているアドレスが違った事が原因だった。テストDBに"find_by"したときに該当のアドレスが存在しないからエラーになっていたのだと思われる。
追記の追記:帰ってくるエラーは"undefined method `name' for nil:NilClass"であったが、該当のメールアドレスが無いからnilが帰っていたという意味を示していることに、今更気づいた。"undefined method 'name'"という書き方なので、なにか変数を作り忘れているのかと思っていた。
describe "正常系テスト" do
before do
fill_in "Name", with: "Example User"
fill_in "Email", with: "[email protected]"
fill_in "Password", with: "foobar"
fill_in "Confirmation", with: "foobar"
end
it "正しく入力して作成ボタンをクリック" do
expect { click_button submit }.to change(User, :count).by(1)
end
describe "Sign Up後のユーザー画面表示" do
before { click_button submit }
let(:user) { User.find_by(email: '[email protected]') }
it { should have_link('Sign out') }
it { should have_title(user.name) }
it { should have_selector('div.alert.alert-success', text: 'Welcome') }
end
end
8.3Cucumberの紹介 (オプション)
これは凄いツールだけど、rspecで十分なので今回はパス。
8.4最後に
ローカルでは全く問題なく動いていたのに、Herokuにアップロードして、Sign upしようとしたら、"We're sorry, but something went wrong."と表示されて先に進めなくなってしまった。ログを調べてみると、remember_tokenでエラーが発生してた。
NoMethodError (undefined method `remember_token=' for #<User:0x00000004070c98>):
app/models/user.rb:23:in `create_remember_token'
app/controllers/users_controller.rb:14:in `create'
ネットで調べてみると、Heroku NoMethod error, remember_token= で、Herokuアプリを再起動したら動いたという話が書いてあったので、"heroku restart"してみたら、無事に解消された。原因がはっきりしないが、"heroku pg:reset"とかを書けた場合は、アプリのリスタートが必要なようだ。
追記:herokuで公開できたのは良いが… "https://<app-name>/user/1"とアクセスするとユーザーページが見えてしまう。いいのだろうか?