のんびりSEの議事録

プログラミング系のポストからアプリに関してのポストなどをしていきます。まれにアニメ・マンガなど

deviseを試してみた

Railsでユーザ認証といったら、deviseが一番有名なのですが、いまいち理解が足りなかったので、実装しながらどんな感じにデータが入るのか等を見ていきたいと思います。

インストー

$ mkdir sample-devise
$ cd sample-devise && rails new . -d mysql -B -T

Gemfile

以下をGemfileに追加(materialzecssはちょっと使ってみたかったのでいれています)

gem 'materialize-rails', '~> 0.97.5.2'
gem 'devise', '~> 4.3'
$ bundle install --path=vendor/bundle

devise設定

devise install

deviseを利用するには、devise:installコマンドを一番最初に実行する必要があります。 作成されるのは、deviseの初期設定ファイルと、devise英語メッセージのようです。

$ rails g devise:install
      create  config/initializers/devise.rb
      create  config/locales/devise.en.yml
===============================================================================

Some setup you must do manually if you haven't yet:

  1. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:

       config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

     In production, :host should be set to the actual host of your application.

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root to: "home#index"

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>

  4. You can copy Devise views (for customization) to your app by running:

       rails g devise:views

===============================================================================

出力された内容にしたがって、deviseの設定をしていく必要があります。

  1. デフォルトURLの設定
  2. root_urlの設定
  3. flashメッセージの設定
  4. deviseのviewを生成

デフォルトURLの設定

デフォルトURLは出力の内容通りに修正しました。

  • config/environments/development.rb
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

モデルの作成

deviseで利用するUserモデルを生成します。

$ rails g devise User
      invoke  active_record
      create    db/migrate/20170611032037_devise_create_users.rb
      create    app/models/user.rb
      insert    app/models/user.rb
       route  devise_for :users

テーブルの作成

$ rails db:create
$ rails db:migrate

作成されたテーブルの内容は以下のとおりです。

$ rails dbconsole
mysql> SHOW CREATE TABLE users \G;
*************************** 1. row ***************************
       Table: users
Create Table: CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `email` varchar(255) NOT NULL DEFAULT '',
  `encrypted_password` varchar(255) NOT NULL DEFAULT '',
  `reset_password_token` varchar(255) DEFAULT NULL,
  `reset_password_sent_at` datetime DEFAULT NULL,
  `remember_created_at` datetime DEFAULT NULL,
  `sign_in_count` int(11) NOT NULL DEFAULT '0',
  `current_sign_in_at` datetime DEFAULT NULL,
  `last_sign_in_at` datetime DEFAULT NULL,
  `current_sign_in_ip` varchar(255) DEFAULT NULL,
  `last_sign_in_ip` varchar(255) DEFAULT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `index_users_on_email` (`email`),
  UNIQUE KEY `index_users_on_reset_password_token` (`reset_password_token`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

最終ログイン時間や、ログインカウント、IP等を記録してくれる設計になっている模様

コントローラの作成

ユーザ認証を掛けるコントローラを生成します。

$ rails g scaffold_controller User
      create  app/controllers/users_controller.rb
      invoke  erb
       exist    app/views/users
      create    app/views/users/index.html.erb
      create    app/views/users/edit.html.erb
      create    app/views/users/show.html.erb
      create    app/views/users/new.html.erb
      create    app/views/users/_form.html.erb
      invoke  helper
      create    app/helpers/users_helper.rb
      invoke  jbuilder
      create    app/views/users/index.json.jbuilder
      create    app/views/users/show.json.jbuilder
      create    app/views/users/_user.json.jbuilder
  • 認証制限を追加

認証を掛けたいcontrollerにauthenticate_モデル名!を追加します。

app/controllers/users_controller.rb

before_action :authenticate_user!

ビューの作成

devise用のviewを作成します。

$ rails generate devise:views users
Expected boolean default value for '--markerb'; got :erb (string)
      invoke  Devise::Generators::SharedViewsGenerator
      create    app/views/users/shared
      create    app/views/users/shared/_links.html.erb
      invoke  form_for
      create    app/views/users/confirmations
      create    app/views/users/confirmations/new.html.erb
      create    app/views/users/passwords
      create    app/views/users/passwords/edit.html.erb
      create    app/views/users/passwords/new.html.erb
      create    app/views/users/registrations
      create    app/views/users/registrations/edit.html.erb
      create    app/views/users/registrations/new.html.erb
      create    app/views/users/sessions
      create    app/views/users/sessions/new.html.erb
      create    app/views/users/unlocks
      create    app/views/users/unlocks/new.html.erb
      invoke  erb
      create    app/views/users/mailer
      create    app/views/users/mailer/confirmation_instructions.html.erb
      create    app/views/users/mailer/email_changed.html.erb
      create    app/views/users/mailer/password_change.html.erb
      create    app/views/users/mailer/reset_password_instructions.html.erb
      create    app/views/users/mailer/unlock_instructions.html.erb

Routing変更

Rails.application.routes.draw do

  resources :users
  root 'users#index'
  
  devise_for :users, controllers: {
    sessions: 'users/sessions'
  },
    path: 'auth',
    path_names: {
      sign_in: 'login',
      sign_out: 'logout',
      password: 'secret',
      confirmation: 'verification',
      unlock: 'unblock',
      registration: 'register',
      sign_up: 'cmon_let_me_in'
    }


  devise_scope :user do
    get 'sign_in', to: 'devise/session#new'
  end
 
end

ログアウト処理

Cookieにdevise_sessionが保存されていて、それを削除するのがsession#destroyメソッドのようです。

rails routes

    ...
    destroy_user_session DELETE /auth/logout(.:format)                  users/sessions#destroy

DELETEで該当URIをcallする

  • app/assets/javascripts/users.js
$(function(){
  'use strict';

  $('#logout').click(function(){
    $.ajax({
      url: "/auth/logout.json",
      method: "DELETE",
      contentType: "application/json"
    }).done(function(data) {
      console.debug(data);
      location.href = "/";
    }).fail(function(data) {
      console.error(data);
    });
  });
});

あとはHTMLに該当ボタンを設置する

user_sessionメソッドでuser sessionを判定する

      <ul id='dropdown1' class='dropdown-content'>
        <% if user_session %>
          <li><a href="#" id="logout">Logout</a></li>
        <% else %>
          <li><a href="/auth/register/cmon_let_me_in" id="sign-up">Sign up</a></li>
          <li><a href="/auth/login" id="login">Login</a></li>
        <% end %>
      </ul>

確認

$ rails s

localhost:3000へアクセスすると、認証していない場合、以下のような認証画面に遷移します。

f:id:tatsu_tora:20170611215312p:plain

認証に成功すると、User一覧画面に遷移することが出来るようになります。

f:id:tatsu_tora:20170611215535p:plain

今回実装したソースは以下に上げています。

github.com

触りは大体こんなもので、実運用に用いるには、もう少し深い部分の理解も必要になってくるかなと思います。

参考

qiita.com