【ログイン機能】rails5でsorceryを実装
プロジェクトの作成
データベースはpostgresqlを指定
バンドルインストールをスキップ
rails new プロジェクト名 -d postgresql -B
Gemfileにsorceryを記載 【Gemfile】
source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby '2.5.1' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' gem 'rails', '~> 5.2.0' # Use postgresql as the database for Active Record gem 'pg', '>= 0.18', '< 2.0' # Use Puma as the app server gem 'puma', '~> 3.11' # Use SCSS for stylesheets gem 'sass-rails', '~> 5.0' # Use Uglifier as compressor for JavaScript assets gem 'uglifier', '>= 1.3.0' # See https://github.com/rails/execjs#readme for more supported runtimes # gem 'mini_racer', platforms: :ruby # Use CoffeeScript for .coffee assets and views gem 'coffee-rails', '~> 4.2' # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks gem 'turbolinks', '~> 5' # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder gem 'jbuilder', '~> 2.5' # Use Redis adapter to run Action Cable in production # gem 'redis', '~> 4.0' # Use ActiveModel has_secure_password # gem 'bcrypt', '~> 3.1.7' # Use ActiveStorage variant # gem 'mini_magick', '~> 4.8' # Use Capistrano for deployment # gem 'capistrano-rails', group: :development ######### 追加したのはココ########## gem 'sorcery' # Reduces boot times through caching; required in config/boot.rb gem 'bootsnap', '>= 1.1.0', require: false group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] end group :development do # Access an interactive console on exception pages or by calling 'console' anywhere in the code. gem 'web-console', '>= 3.3.0' gem 'listen', '>= 3.0.5', '< 3.2' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring' gem 'spring-watcher-listen', '~> 2.0.0' end group :test do # Adds support for Capybara system testing and selenium driver gem 'capybara', '>= 2.15', '< 4.0' gem 'selenium-webdriver' # Easy installation and use of chromedriver to run system tests with Chrome gem 'chromedriver-helper' end # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
ターミナルで
bundle
として、bundle install…
rbenv: bundle: command not found The `bundle' command exists in these Ruby versions: 2.2.3
おっと、こんなエラーが出た場合は…
gem install bundler
を実行してから再度bundle installする。
無事にインストールが完了する。
その後
rake db:create
でデータベースを作成。
sorceryの導入
ターミナルで
rails g sorcery:install
create config/initializers/sorcery.rb generate model User --skip-migration invoke active_record create app/models/user.rb invoke test_unit create test/models/user_test.rb create test/fixtures/users.yml insert app/models/user.rb insert app/models/user.rb
こんな感じでファイルが生成されるが何か足りない…
マイグレファイルなくね!?
調べたところ、sorceryがrailsの最新版(この時点で5.2)に対応していなかったらしく、githubから最新版を指定してbundle installする必要があるとのこと。
先程のGemfileのsorceryの箇所を、
gem 'sorcery', github: 'sorcery/sorcery'
にして、先程生成したファイルを削除。
rails d sorcery:install
すると、
remove config/initializers/sorcery.rb generate model User --skip-migration subtract app/models/user.rb subtract app/models/user.rb
となるので、再度
rails g sorcery:install
create config/initializers/sorcery.rb
generate model User --skip-migration
invoke active_record
identical app/models/user.rb
invoke test_unit
identical test/models/user_test.rb
identical test/fixtures/users.yml
insert app/models/user.rb
insert app/models/user.rb
create db/migrate/20181004061537_sorcery_core.rb
マイグレファイルが無事作成された。
【db/migrate/20181004061537_sorcery_core.rb】
class SorceryCore < ActiveRecord::Migration[5.2] def change create_table :users do |t| t.string :email, :null => false t.string :crypted_password t.string :salt t.timestamps :null => false end add_index :users, :email, unique: true end end
問題なければ
rake db:migrate
※Userテーブルの項目を変更したい場合はmigrateファイルを変更してから
User登録機能の作成
scaffoldで一気にファイル生成
ターミナルで
rails g scaffold user email:string crypted_password:string salt:string --migration false
とすると、必要なファイル(必要ないファイルも)が一気に生成される。
フォームのcrypted_passwordとsaltの項目名を変更し、text_fieldからpassword_fieldに。
【view/users/_form.html.erb】
<div class="field"> <%= form.label :password %> <%= form.password_field :password %> </div> <div class="field"> <%= form.label :password_confirmation %> <%= form.password_field :password_confirmation %> </div>
また、ストロングパラメーターも更新しておく必要がある。
【controllers/users_controller.rb】
def user_params params.require(:user).permit(:name, :email, :gender, :age, :password, :password_confirmation) end
バリデートの設定
【models/user.rb】
class User < ActiveRecord::Base authenticates_with_sorcery! validates :name, :email, :gender, :age, presence: true validates :password, length: { minimum: 4 }, if: -> { new_record? || changes[:crypted_password] } validates :password, confirmation: true, if: -> { new_record? || changes[:crypted_password] } validates :password_confirmation, presence: true, if: -> { new_record? || changes[:crypted_password] } validates :email, uniqueness: true end
http://localhost:◯◯◯◯/usersにアクセスするとUserを作れるようになっている。
認証機能(ログイン)
Userの操作ができたので、次はログイン機能を実装。
ターミナルで
rails g controller UserSessions new create destroy
を実行。
ログイン・ログアウトに必要なファイルが一気に生成される。
controllerの実装
こんな感じで書き込む。
【controllers/user_session_controller.rb】
class UserSessionsController < ApplicationController def new @user = User.new end def create if @user = login(params[:email], params[:password]) redirect_back_or_to(:users, notice: 'Login successful') else flash.now[:alert] = 'Login failed' render action: 'new' end end def destroy logout redirect_to(:users, notice: 'Logged out!') end end
viewの実装
app/views/user_sessions内のcreate.html.erbとdestroy.html.erbは要らないので削除。
new.html.erbにログインフォームを実装。
【views/user_sessions/new.html.erb】
<h1>Login</h1> <%= form_tag login_path, method: :post do %> <div class="field"> <%= label_tag :email %><br /> <%= text_field_tag :email %> </div> <div class="field"> <%= label_tag :password %><br /> <%= password_field_tag :password %> </div> <div class="actions"> <%= submit_tag "Login" %> </div> <% end %>
Routesの設定
【config/routes.rb】
Rails.application.routes.draw do resources :users get '/login' => 'user_sessions#new', as: :login post '/login' => 'user_sessions#create' delete '/logout' => 'user_sessions#destroy', as: :logout root 'user_sessions#new' end
ヘッダーにナビゲーションボタンを設置
【views/layout/application.html.erb】
<!DOCTYPE html> <html> <head> <title>SportCircle</title> <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> </head> <body> <div id="nav"> <% if current_user %> <%= link_to "Edit Profile", edit_user_path(current_user.id) %> <%= link_to "Logout", :logout, method: :post %> <% else %> <%= link_to "Register", new_user_path %> | <%= link_to "Login", :login %> <% end %> </div> <div> <p id="notice"><%= flash[:notice] %></p> <p id="alert"><%= flash[:alert] %></p> </div> <%= yield %> </body> </html>
before_actionでログインフィルターをかける
ログインしていない場合はコンテンツを見れないようにする。
逆に、アカウント登録やログイン画面などはログアウトしている状態でないといけない。
【controllers/application_controller.rb】
class ApplicationController < ActionController::Base before_action :require_login end
【acontrollers/users_controller.rb】
class UsersController < ApplicationController skip_before_action :require_login, only: [:index, :new, :create] end
【controllers/user_sessions_controller.rb】
class UserSessionsController < ApplicationController skip_before_action :require_login, except: [:destroy] end
URL直打ちアクセスの防止
ログインしていない状態のときにURL直打ちで直接アクセスされるとページが見れてしまうので、
application_controllerにプライベートメソッドを追加。
【controllers/application_controller.rb】
private def not_authenticated redirect_to login_path, alert: "Please login first" end
loginやcurrent_userが使えない!
ブラウザで確認したところ、current_userでエラー。
current_userの箇所をコメントアウトしてログインを試してみてもloginでエラー。
なんで???
詳しい原因はわからないが、githubから呼んでいるsorceryが新しすぎる?らしい。
Gemfileのgem 'sorcery', github: 'sorcery/sorcery'
をコメントアウトして、代わりにgem 'sorcery'
でbundle installしたら問題なく動いた。
まとめ
- 導入はかなり簡単!
- 公式チュートリアル(Simple Password Authentication · Sorcery/sorcery Wiki · GitHub)が分かりやすい
- シンプルなログイン機能ならオススメ
- バージョンには気をつける