【Rails】認証機能を実装するdeviseの導入方法

スポンサーリンク

Webアプリケーションにおいて簡単にログイン認証などを実装できる Devise の導入方法です。最初に必要そうな部分をまとめてます。

Deviseの導入

実行環境は以下の通りです。

  • Rails 5.1.1
  • Ruby 2.4.1

Gemfile に以下を追加してbundle installを実行してください。

gem 'devise'

Devise の設定ファイルを生成します。

$ ./bin/rails generate devise:install
Running via Spring preloader in process 55270
      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

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

1 はメールに記載されるURLのホストを指定します。config/environments/development.rbに以下を追加してください。

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

2 はroot_urlを設定してない場合は追加してください。

3 はエラーメッセージ用のタグです。app/views/layouts/application.html.hamlに追加してください。haml を使用してます。

    %p.notice= notice
    %p.alert= alert

4 は View のパートで説明します。

Getting started | plataformatec/devise · GitHub

モデルの作成

Devise 用のモデルを作成します。作成されたモデルには Devise モジュールで構成され、Devise のコントローラを指すようにルーティングが追加されます。

$ ./bin/rails g devise User
Running via Spring preloader in process 55534
      invoke  active_record
      create    db/migrate/20170617153827_devise_create_users.rb
      create    app/models/user.rb
      invoke    rspec
      create      spec/models/user_spec.rb
      invoke      factory_girl
      create        spec/factories/users.rb
      insert    app/models/user.rb
       route  devise_for :users

作成された User モデルを確認して必要なモジュールを追加してください。:omniauthable以外は追加しました。

class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable,
         :lockable, :confirmable, :timeoutable
end

マイグレートファイルを確認して追加したモジュールのコメントを外してください。以上の準備ができたらテーブルを作成します。

$ ./bin/rails db:create db:migrate
Created database 'example_development'
Created database 'example_test'
== 20170617153827 DeviseCreateUsers: migrating ================================
-- create_table(:users)
   -> 0.0304s
-- add_index(:users, :email, {:unique=>true})
   -> 0.0219s
-- add_index(:users, :reset_password_token, {:unique=>true})
   -> 0.0327s
-- add_index(:users, :confirmation_token, {:unique=>true})
   -> 0.0092s
-- add_index(:users, :unlock_token, {:unique=>true})
   -> 0.0093s
== 20170617153827 DeviseCreateUsers: migrated (0.1042s) =======================

Viewの設定

Devise の全ての View は Gem の中にパッケージングされてます。カスタマイズしたい場合はrails g devise:viewsを実行すると全ての View がapp/views/devise配下にコピーされます。

しかし、User モデルを作成しているのに対応する View がapp/views/deviseにあると分かり辛いです。その場合は、以下のようにモデルのスコープを指定して作成してください。

$ ./bin/rails g devise:views users
Running via Spring preloader in process 59595
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

これでapp/views/users配下に Devise の View がコピーされましたが、このままではこの View が呼び出されることはありません。/users/sign_inにアクセスすると Gem にパッケージングされてる View を呼び出してます。これはデフォルトのスコープがapp/view/devise配下を探しにいってるためです。

tarted GET "/users/sign_in" for 127.0.0.1 at 2017-06-18 15:27:36 +0900
Processing by Devise::SessionsController#new as HTML
  Rendering vendor/bundle/ruby/2.4.0/gems/devise-4.3.0/app/views/devise/sessions/new.html.erb within layouts/application

解決するにはvi config/initializers/devise.rbで以下の箇所のコメントアウトを外してtrueに変更してください。

config.scoped_views = true

この変更によってapp/views/usersが優先されるようになります。

Started GET "/users/sign_in" for 127.0.0.1 at 2017-06-18 15:28:12 +0900
Processing by Devise::SessionsController#new as HTML
  Rendering users/sessions/new.html.erb within layouts/application

Admin など復数の Devise モデルがある場合も同様です。

View は erb で作成されているので haml を使ってるならgem 'haml-rails'の Rake タスクで変換できます。

$ ./bin/rake haml:erb2haml

Configuring views | plataformatec/devise · GitHub
How To: Create Haml and Slim Views · plataformatec/devise Wiki · GitHub

Controllerの設定

Controller をカスタマイズしたい場合rails generate devise:controllers [scope]を実行すると、指定したスコープで Devise コントローラを継承したカスタムコントローラが作成されます。

$ ./bin/rails generate devise:controllers users
Running via Spring preloader in process 63136
      create  app/controllers/users/confirmations_controller.rb
      create  app/controllers/users/passwords_controller.rb
      create  app/controllers/users/registrations_controller.rb
      create  app/controllers/users/sessions_controller.rb
      create  app/controllers/users/unlocks_controller.rb
      create  app/controllers/users/omniauth_callbacks_controller.rb

作成されたコントローラを見ると Devise を継承してるだけで何も書かれていません。

class Users::SessionsController < Devise::SessionsController
end

カスタマイズしたい場合は単純にメソッドをオーバーライドするか、Devise のメソッドはブロックを受け取れるようになってるので以下のように新しい処理を追加しましょう。

  def create
    super do |resource|
      # custom code
    end
  end

また、カスタムコントローラを使用するにはルーティングの変更が必要です。

Configuring controllers | plataformatec/devise · GitHub

ルーティングの変更

config/routes.rbを確認するとdevise_for :usersが追加されていると思います。この状態でのルーティングは以下のようになっています。

        new_user_session GET    /users/sign_in(.:format)          devise/sessions#new
            user_session POST   /users/sign_in(.:format)          devise/sessions#create
    destroy_user_session DELETE /users/sign_out(.:format)         devise/sessions#destroy
...

このままだと作成したカスタムコントローラを向いてないため以下のようにUsersを module に指定してください。

Rails.application.routes.draw do
  devise_for :users, module: :users
end

これで Users モジュールのコントローラにルーティングされました。

        new_user_session GET    /users/sign_in(.:format)          users/sessions#new
            user_session POST   /users/sign_in(.:format)          users/sessions#create
    destroy_user_session DELETE /users/sign_out(.:format)         users/sessions#destroy

Configuring routes | plataformatec/devise · GitHub
devise_for — Documentation for plataformatec/devise (master)

日本語化

Gemfile に以下を追加してbundle installを実行してください。

gem 'devise-i18n'

config/application.rbにデフォルト locale の指定を追加してください。

config.i18n.default_locale = :ja

rails g devise:viewsで作成される View は I18n に対応していなかったため、devise-i18nで作成し直します。

$ ./bin/rails g devise:i18n:views users
      invoke  Devise::I18n::SharedViewsGenerator
       exist    app/views/users/shared
      create    app/views/users/shared/_links.html.erb
      invoke  Devise::I18n::MailerViewsGenerator
...
$ ./bin/rake haml:erb2haml

rails g devise:i18n:localeで locale ファイルを作成します。View のスコープを User に変更してる場合はファイル内のdeviseという記述をusersに変更しましょう。

$ ./bin/rails g devise:i18n:locale ja
      create  config/locales/devise.views.ja.yml
$ ./bin/rails g devise:i18n:locale en
      create  config/locales/devise.views.en.yml

始めに作成されていた locale ファイルは削除してください。

$ rm config/locales/devise.en.yml

I18n | plataformatec/devise · GitHub
I18n · plataformatec/devise Wiki · GitHub
GitHub - tigrish/devise-i18n: Translations for the devise gem