Railsチュートリアル9章 クッキー(remember_me)

Railsチュートリアル9章で大事なとこをメモっていきます。

テストコードはRspecを使っています。

 

ランダムトークン生成

user.rb

def User.new_token
SecureRandom.urlsafe_base64
ここ!!これで22文字のランダムな文字列を作っている。
end

user.rb

def remember
self.remember_token = User.new_token
先ほど生成したやつをトークンとしている
update_attribute(:remember_digest, User.digest(remember_token))
remember_tokenをdigestすることでハッシュ化している。ハッシュ化したremember_tokenを
 regember_digestカラムに入れている
end

---------------------------------------------------------------------------------------

クッキーにuser_id, remember_tokenを入れる

sessions_helper.rb

def remember(user)
user.remember *上のremember(userモデル内)
cookies.permanent.signed[:user_id] = user.id
     permanentで永続化している。
     signedは署名付きクッキー。cookiesをブラウザに保存する前に安全に暗号化している。セキュリティー対策
   idの取り出し方:cookies.signed[:user_id]で自動で暗号が解除できる
cookies.permanent[:remember_token] = user.remember_token
end

 

---------------------------------------------------------------------------------------

authenticateメソッド

def authenticated?(remember_token)
return false if remember_digest.nil?
BCrypt::Password.new(remember_digest).is_password?(remember_token)
newここ!
          ハッシュ化されたremember_digestとハッシュ化されていないremember_tokenが合致するかを
          行っている
end

 

ちなみに前章ではハッシュ化するメソッドを取り扱った。

digestメソッドである。

def User.digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
        ここに注目!!crateである。

newとcreateの違いがあることに気がついた。

 

---------------------------------------------------------------------------------------

モデルとヘルパーについて

モデルに書いたり、ヘルパーに書いたり行ったり来たりしている。なぜだろうか。

 

UserにまつわるメソッドはUserモデルに書かなければならない。

Sessionコントローラーで使うメソッドはSession関連に書かなければならない。

Sessionモデルは存在しない。Sessionヘルパーに書く。UserモデルはSessionじゃないので書くのはおかしい。

だからモデルとヘルパーそれぞれに書かないといけない。

 

---------------------------------------------------------------------------------------

テストコード

sessionやcookiesはsystem specでの書き方がわからなかったので(目に見えないから)そのため今回はrequest spechelper specも使用した。

request spec: コントローラーにまつわるテスト

helper spec: ヘルパーにまつわるテスト

 

まずはモデルテスト1つ追加

user_spec.rb

it "authenticated? should return false for a user with nil digest" do
expect(@user.authenticated?('')).to be_falsy 
                      ここfalthyじゃないので注意ね。trueはtruthyだけど。
end

 

追加!!複数のタブでログアウト

ログインしていないとログアウトリンクが見当たらないためsystemでは書けなかった。

visitはできない。destroyはビューないため。

 

サポートモジュール追加した。ログインしているかどうか判断する。

is_login?メソッド。ログインしているかどうかを判断するメソッドはヘルパーのメソッドであったため、サポートモジュールに入れて使えるようにする。

 

module LoggedIn
def is_login?
!session[:user_id].nil?
end

sessions_spec.rb

RSpec.describe "Sessions", type: :request do
                    ここ!
before do
@user = FactoryBot.create(:user)
end
# let(:user) { FactoryBot.create(:user) }

it '二つのタブでログアウト' do
delete logout_path
expect(response).to redirect_to root_path
expect(is_login?).to be_falsy
     ここね。

end

 

request spec と helper spec

 

サポートモジュール(ログイン用)

module LoggedIn
ここからはsystem用
def log_in(user)
visit login_path
fill_in 'Email', with: user.email
fill_in 'Password', with: user.password
check 'Remember me on this compute'
find('input[name="commit"]').click
expect(current_path).to eq(user_path(user))
 
end

 
 
ここからrequest用
# request
def log_in_as(user, remember:'1')
post login_path, params:{session:
{email: user.email,password: user.password,remember_me: remember}
}
end

end

 

system/sessions_spec.rb

requestやhelperも system内に書いちゃっておk

RSpec.describe "Sessions", type: :request do
                   ここ!!
before do
@user = FactoryBot.create(:user)
end
# let(:user) { FactoryBot.create(:user) }
記事にはlet使われてるけどbeforeで全然問題ない

it 'login with remembering' do
log_in_as(@user, remember:'1') サポートモジュールで定義したやつ使う
expect(cookies[:remember_token]).not_to eq nil
end

it "login without remembering" do
log_in_as(@user, remember:'0') こっちでは0にしてチェックを入れないようにしている
expect(cookies[:remember_token]).to eq nil
end

end

RSpec.describe SessionsHelper, type: :helper do
       これ文字列じゃないので注意   ここでヘルパーテストするよ〜
# SessionsHelperについてテストしますよ typeはhelperで
 SessionsHelperを入れてヘルパーテストをする理由は
 current_userを使いたかったから。でもこれもサポートモジュールに入れればヘルパーテストじゃなくてもいけるかと思う。
before do
@user = FactoryBot.create(:user)
remember(@user)
end
 

it 'current_user returns right user when session is nil' do
expect(current_user).to eq @user
expect(is_login?).to be_truthy
end

it "current_user returns nil when remember digest is wrong" do
@user.update_attribute(:remember_digest, User.digest(User.new_token))
expect(current_user).not_to eq @user
expect(is_login?).to be_falsy
end

end

 

以上で9章終わりです!