心はいつも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

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

  関連記事

no image
Homebrewをインストールする。

MacOS 10.8.5(Mountain Lion)にRuby&Ru …

パーフェクトRuby 3章制御構造/メソッド/組み込み関数 3-1演算子

パーフェクトRuby2章の後は6章をやろうと思っていましたが、やっぱり順番にやっ …

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

6.2.4フォーマットを検証する です。 メールアドレスは文字数制限だけじゃだめ …

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

仕様の探求 userモデルには、登録と認証、承認に必要なモデルは既に作ってありま …

no image
ヘルパーメソッドを自作する

便利なrailsのヘルパーメソッド。自分でも作れます。 作るときは、 アプリのd …

no image
Gitをインストールする

Rails開発がしたいのですが、今後必要になるでしょうからGitをインストールし …

カスペルスキーを使っています

PCのウィルススキャンは、多くの人が使っているかと思います。 大手3社のソフトを …

詳解 Objective-C 2.0 第3版 CHAPTER2 Objective-Cのプログラム

Objective-Cの解説はメッセージから始まる。このメッセージという概念、も …

no image
@で始まるのが インスタンス変数

@ で始まるのが インスタンス変数 大文字で始まるのが 定数 文法書のどこに書い …

no image
formatはどこから取ってくる?

ruby on rails3プリケーションプログラミングの本の内容をruby2. …