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の設定をしていく必要があります。
- デフォルトURLの設定
- root_urlの設定
- flashメッセージの設定
- 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へアクセスすると、認証していない場合、以下のような認証画面に遷移します。

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

今回実装したソースは以下に上げています。
触りは大体こんなもので、実運用に用いるには、もう少し深い部分の理解も必要になってくるかなと思います。