Deviseの使い方

Deviseのインストール

Gemのインストール

 gem 'devise'
bundle install
rails g devise:install

ユーザーモデルの作成(migrationファイルも含まれる)

rails g model hogehogeではなく、devise用のコマンドを利用する。

rails g devise user
$ rails g devise user
invoke  active_record
create    db/migrate/20190719114302_devise_create_users.rb
create    app/models/user.rb
invoke    test_unit
create      test/models/user_test.rb
create      test/fixtures/users.yml
insert    app/models/user.rb
 route  devise_for :users

ここでroute,rbに自動的に追記されるdevise_forはログイン関係に必要なルーティングを一気に生成してくれるdeviseのヘルパーメソッド。

テーブルの作成

migrationファイルを編集して必要な情報を足す。

class DeviseCreateUsers < ActiveRecord::Migration[5.0]
  def change
    create_table :users do |t|
      ## Database authenticatable
      t.string :name,               null: false, unique: true, index: true
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""

db作成。rails db:migrateでOK

bundle exec rake db:migrate

サーバーの再起動

$ rails s

必要ならテーブルに必要な入力項目を足す。

rails g migration AddNameToUser name:string
bundle exec rake db:migrate

routesを通す。

TechReviewSite::Application.routes.draw do

  devise_for :users
  resources :users, only: :show
  resources :products, only: :show do
    resources:reviews, only:[:new, :create]
    collection do
      get 'search'
    end
  end
  root 'products#index'
end

ビューファイルの作成

通常のままだとviewフォルダ内にusers関係のファルダがないため変更可能にします。

rails g devise:views

app/views/users/sessions/new.html.erb
サインインページ等の編集をする。

これだけだと動かないのでconfigファイルを編集して以下をtrueへ変更。

config/initializers/divise.rb
#config.scoped_views = false
↓
config.scoped_views = true

ログインを強制する

コントローラに以下を追記してアクションを制限する。

before_action :authenticate_user!, only: :search

deviseのストロングパラメーターを追加する

通常、入力した情報はパラメーターとして受け取り、コントローラーのストロングパラメーターで制御できる。
deviseでログイン機能を実装した場合、ログイン時に送られてくるパラメーターを制限するストロングパラメーターは、deviseのGem内に記述されているため編集できない。

configure_permitted_parametersメソッドを用いて追加したいキーを指定する。
application_controller.rbにbefore_actionで記述する。

before_action :configure_permitted_parameters, if: :devise_controller?

def configure_permitted_parameters
 devise_parameter_sanitizer.permit(:ストロングパラメーターを追加したいアクション名, keys: [:追加するキー])
end
  具体例
  class ApplicationController < ActionController::Base
    # Prevent CSRF attacks by raising an exception.
    # For APIs, you may want to use :null_session instead.
    protect_from_forgery with: :exception
    before_action :configure_permitted_parameters, if: :devise_controller?

    def configure_permitted_parameters
      devise_parameter_sanitizer.permit(:sign_up, keys: [:nickname])
    end
  end

controllerの作成

rails g controller users

デフォルトのコントローラーをオーバーライドする場合、

rails g devise:controllers users
+routesにも追記が必要

Deviseで使えるメソッド

after_sign_out_path_forメソッド

deviseでサインアウトしたあとのリダイレクト先を指定するメソッドとしてafter_sign_out_path_forがあります。このメソッドでは返り値にサインアウト後のリダイレクト先URLを指定します。deiviseのメソッドを上書きしている関係上resourceを引数に渡さなけらばならないので、resourceを引数に渡します。

def after_sign_out_path_for(resource)
  '/users/sign_in' # サインアウト後のリダイレクト先URL
end

authenticate_user!

deviseをインストールすると、ログイン画面とサインアップ画面を自動で用意してくれます。authenticate_user!はdeviseをインストールすることで使えるメソッドです。ユーザーがログインしているかどうかを確認し、ログインしていない場合はログインページにリダイレクトします。通常、before_actionを合わせて使用します。before_actionのexceptやonlyオプションを組み合わせると特定のアクションを指定することもできます。

before_action :authenticate_user!, only: :new

devise_parameter_sanitizer

devise_parameter_sanitizerメソッドを使うとdeviseで設定されているstrong_parametersに対してパラメーターを追加できる。
devise_parameter_sanitizerメソッドはbefore_actionに設定する。
これはdeviseの処理なので、Deviseのコントローラを継承したコントローラかもしくはApplicationControllerに記述する。この際に直接before action内にdevise_parameter_sanitizerを書いてはいけない(なぜ?)

devise_parameter_sanitizer.permit(追加したいメソッドの種類, keys: [追加したいパラメーター名])

指定する引数は2つ。1つ目が「StrongParametersを追加したい処理の種類」

引数の値処理
:sign_up新規登録時
:sign_inログイン時
:account_updateレコードの更新時

2つ目の引数には追加したいパラメーター名を渡す。
複数の場合は,(カンマ)区切りで渡す。

devise_parameter_sanitizer.permit(追加したいメソッドの種類, keys: [:パラメーター1, :パラメーター2,..])
class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception
  before_action :configure_permitted_parameters if: :devise_controller?

  def after_sign_out_path_for(resource)
    '/users/sign_in' # サインアウト後のリダイレクト先URL
  end

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up,keys: [:avatar, :nickname]) 
  end
end

devise_parameter_sanitizerメソッドはdeviseで追加されたメソッドなので、Deviseのコントローラ以外で呼び出せない。よって、before_actionを適応するコントローラを指定する。

before_action :メソッド名, if: :コントローラ名?

user_signed_in?

サインインしていればtrueを、していなければfalseを返す。
before_action等で制御するときになどによく使う。

unless user_signed_in?
  puts 'ログインをしてください'
end

ユーザーをサインインさせる。

sign_inにインスタンスを渡すとサインインできる。
ウィザード形式のフォームの場合などに事後でサインインさせる時に使う。

sign_in User.find(session[:id]) unless user_signed_in?

controllerのoverride

registrationsをオーバーライドするには以下のように記載し、
devise/registrations -> users/registrationsへ参照先を変更する。

  devise_for :users, controllers: {
    registrations: 'users/registrations'
  }

scopeを設定することでアクションを追加できる。

  devise_scope :user do
    post '/users/sign_up/payment_confirmation', to: 'users/registrations#payment_confirmation'
    get '/users/sign_up/complete', to: 'devise/registrations#complete'
    get '/users/logout', to: 'devise/registrations#user_logout'
  end

メモ書き

ユーザーページの実装

ユーザー個別のページは/users/1 ~ /users/99などと振られるIDによりページ名が異なる。

Rails.application.routes.draw do
  devise_for :users
  get   'users/:id'  => 'users#show'
end

users/:idとすることでパラメーターにハッシュ形式で値を持たせることができる。
params[:id]とすればコントローラーがidを取り出せる。

errors

user exists

空のデータベースに対して登録しようとした時、下記のエラーが出る。
エラー名と実態が一致していないケースで、validationエラーの可能性が高い。
多いのはdeviseの標準のpassword8文字以上を満たしていないケース。

User Exists (0.5ms)[0m  [1mSELECT 1 AS one FROM "users" WHERE "users"."email" = 'hoge@mst.com' LIMIT 1

Undefined method users_url

deviseもコントローラーをオーバーライドした際に、sign_up後の遷移先に移る際にこのエラーがでた。
after_sign_up_path_forを書き換えてもエラーが消えなかったため、createアクションをオーバーライドして、redirectするように変更して解消した。
エラーの原因や解決方法がよくわからない。

Active Storage

画像アップロード用のgemであるActive Storageを使う。

ImageMagick

ImageMagickという画像変換ツールと、それをRailsから使うためのmini_magickというgem

brew install imagemagick

gemfile

gem 'mini_magick'
bundle install

インストールが終わったらサーバーの再起動

Active Storageのインストール

rails active_storage:install
rails db:migrate

Userモデルに設定を追加

user.rb

class User < ApplicationRecord
  #Include default devise modules. Others available are:
  #:confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  has_one_attached :avatar
end

画像の出力

ユーザー登録に画像を登録させる際に使う。
登録された画像を利用する際には下記のようにする。

<%= image_tag current_user.avatar %></div>

bcrypt

パスワード暗号化してくれる。Deviseでも使われている。

以下を記載してbundle install

gem 'bcrypt'

暗号化パスワードを利用したいモデルに以下のように記述する。

class Hoge < ApplicationRecord
  has_secure_password
end

hoge.saveする際にはformでpasswordとpassword_confirmationの2つを渡せば自動的にエンコードしてくれる。エンコードされたパスワードはpassword_digestに格納される。

migrateファイルに以下カラムを足す。

t.string :password_digest

deviseでbcryptを利用する場合にはpassword_digestではなく、encrypted_passwordという名称になる。

パスワードの認証 authenticate()

引数にパスワードを渡して、インスタンスに適応すると、パスワードが一致していればtrue、違えばfalseを返す。

@hoge.authenticate("hogehoge")

コメント