心はいつもAirPucci (空元気でもいいから)

毎日がPucciを着ているような気分

RailsTutorial4.0を高速で復習する。8.2.1章。途中から。

   


Railsのセキュリティに納得がいかず3日ほど低速です。とりあえず進めています。

コールバックで記憶トークンを生成

コールバックについてはこちらがまとまっていました。
Railsのコールバックまとめ

コールバックとは、バリデーションの実行やデータベースへの保存などのタイミングで処理を行うための機能です。あるタイミングで必ず実行する必要がある処理をコールバックに指定することで、モデルの一貫性を保つことができます。

とのこと。

まずはテスト書き。
リスト8.17 記憶トークンが有効である (空欄のない) ことをテストする。
spec/models/user_spec.rb

require 'spec_helper'

describe User do

  before do
    @user = User.new(name: "Example User", email: "user@example.com",
                     password: "foobar", password_confirmation: "foobar")
  end

  subject { @user }
略
  describe "remember token" do
    before { @user.save }
    its(:remember_token) { should_not be_blank }
  end
end

コールバックで絶対:remember_token保存するので、保存されているかのテストですね。

itsメソッドは引数として与えられたその属性 (この場合は:remember_token) に対してテストを行うときに使用するとのこと。

its(:remember_token) { should_not be_blank }
つまり、上のコードは以下と等価です。
it { expect(@user.remember_token).not_to be_blank }

トークンを保存

リスト8.18 before_createコールバックを使用して remember_token属性を作成する。
app/models/user.rb

class User < ActiveRecord::Base
  before_save { self.email = email.downcase }
  before_create :create_remember_token
略
  def User.new_remember_token
    SecureRandom.urlsafe_base64
  end

  def User.encrypt(token)
    Digest::SHA1.hexdigest(token.to_s)
  end

  private

    def create_remember_token
      self.remember_token = User.encrypt(User.new_remember_token)
    end
end

これがコールバックで、トークンを(インスタンスに)保存しています。ところでインスタンスに保存=結局はDBに保存ってことでいいのか?
before_create :create_remember_token
元ネタがprivateに書いてあります。
privateキーワード以降で定義されたメソッドはすべて隠蔽されます。つまり外部からの直たたきはできないってことか。

ん、これならセッション事に新しいトークンができていることになってるの?

=>before_createはオブジェクトが登録されるときに実行されるので(今回はremember_token属性が無いときにremember_tokenを登録)セッション毎に新しいトークンではなく、新規ユーザー登録事に新しいトークンです。クッキーが盗まれたらどうなるんだろうか。

8.2.2正しいsign_inメソッド、です。

sign_inメソッドは、sessions_controller.rbのcreateで呼んでいる。セッションを作るとき=ユーザーがログイン成功する時に呼んでいます。

仕様の確認

記憶トークンをブラウザのcookiesに保存し、ユーザーが別のページに移動するときにそのトークンを使用してデータベース内のユーザーのレコードを見つけ

とのことですが、これでいいのか?

0) ユーザーがログインする。
1) トークンを新規作成する。
2) 暗号化されていないトークンをブラウザのcookiesに保存する。
3) 暗号化したトークンをデータベースに保存する。
4) 与えられたユーザーを現在のユーザーに設定する

sign_inメソッドの実装

リスト8.19 完全だがまだ動作しないsign_in関数。
リスト8.22 remember_tokenを使用して現在のユーザーを検索する。
リスト8.23 signed_in?ヘルパーメソッド。
app/helpers/sessions_helper.rb

module SessionsHelper

  def sign_in(user)
    remember_token = User.new_remember_token
    cookies.permanent[:remember_token] = remember_token
    user.update_attribute(:remember_token, User.encrypt(remember_token))
    self.current_user = user
  end

  def signed_in?
    !current_user.nil?
  end

def current_user=(user)
    @current_user = user
  end

  def current_user
    remember_token = User.encrypt(cookies[:remember_token])
    @current_user ||= User.find_by(remember_token: remember_token)
  end
略
end

このsign_in(user)のuserは
user = User.find_by(email: params[:session][:email].downcase)
なので、入力情報でDBカらひっぱってきたユーザー情報ですね。

update_attributeでuserのremember_token要素を保存していますが、update_attributeはRails4非推奨じゃないんだろうか?

!current_user.nil?は、current_userが定義されていない.nilくない!だから、current_userがいる=true=ログインしているってことですね。

8.2.3現在のユーザー、です。

sessions_helper.rbで
current_user=という、終わりに=がついたメソッドを定義しています。これはrubyの機能だそうで、んーもっと勉強しないと。

self.current_user = …
自動的に以下のコードに置き換えられます。
current_user=(…)

Rubyは ()書かなくてもいいけど、この場合()がないとわかりづらそうです。

8.2.4レイアウトリンクを変更する、です。

ログインしている、していないで表示を変える

ログインしているときは、ログイン用のメニューにするってことです。

リスト8.24 サインインしているユーザー用にリンクを変更する。
app/views/layouts/_header.html.erb

<header class="navbar navbar-fixed-top navbar-inverse">
  <div class="navbar-inner">
    <div class="container">
      <%= link_to "sample app", root_path, id: "logo" %>
      <nav>
        <ul class="nav pull-right">
          <li><%= link_to "Home", root_path %></li>
          <li><%= link_to "Help", help_path %></li>
          <% if signed_in? %>
            <li><%= link_to "Users", '#' %></li>
            <li id="fat-menu" class="dropdown">
              <a href="#" class="dropdown-toggle" data-toggle="dropdown">
                Account <b class="caret"></b>
              </a>
              <ul class="dropdown-menu">
                <li><%= link_to "Profile", current_user %></li>
                <li><%= link_to "Settings", '#' %></li>
                <li class="divider"></li>
                <li>
                  <%= link_to "Sign out", signout_path, method: "delete" %>
                </li>
              </ul>
            </li>
          <% else %>
            <li><%= link_to "Sign in", signin_path %></li>
          <% end %>
        </ul>
      </nav>
    </div>
  </div>
</header>

ログイン済のときは、”Profile”,”Settings”,”Sign out”へのリンクができました。

リスト8.25 Bootstrap JavaScriptライブラリをapplication.jsに追加する。
app/assets/javascripts/application.js

//= require jquery
//= require jquery_ujs
//= require bootstrap
//= require turbolinks
//= require_tree .

ちょっとここでいったんコミット
次は、
8.2.5ユーザー登録と同時にサインインする
です。

 - テクニカル ,

Message

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

  関連記事

RailsTutorial4.0を高速で復習する。5.1.2章。

5.1.2BootstrapとカスタムCSS、です。 今までdivについていたイ …

no image
RailsTutorial4.0を高速で復習する。10.2章。

10.2マイクロポストを表示する、です。 ポストの投稿ではなく、表示だけを先に作 …

no image
RailsTutorial4.0を高速で復習する。3.1章。

3.1章は静的ページの追加。これをトップページとして後で色々追加していきます。 …

Ruby on Railsを4.1.0にバージョンアップする

真央ロス真央廃を超えた腐まお状態な1ヶ月1週間、まるで娘が嫁に行った父親のごとし …

no image
Ruby on Railsのインストール

Rubyのアップデートが終わったので、いよいよRailsをインストールします。 …

no image
RailsTutorial4.0を高速で復習する。3.3.4章。

3.3.4レイアウトを使って重複を解消する、です。 ここでapplication …

no image
RailsTutorial4.0を高速で復習する。9.3章。

9.3すべてのユーザーを表示する、です。 いろいろ細かい実装するまえにこれやるべ …

no image
いまだにユビキタスなSONYとクラウドに向かうApple

PS3のトルネが良さそう@ヤマダ電機。PS3本体とチューナーの2台になってスッキ …

RailsTutorial4.0を高速で復習する。5章。

さてRailsTutorial4.0も5章に入ります。まだ序の口です。5章ではb …

no image
accepts_nested_attributes_for

everydayRailsやっていて、 phoneモデルのテストのところで ac …