LoginSignup
11
17

More than 3 years have passed since last update.

【備忘録】Rails6 Devise + cancancan の使い方

Last updated at Posted at 2020-05-23

はじめに

deviseを使用してUserモデル(認証)を作成後して
cancancanを追加して認可をできるようにしました。

その過程を備忘録としてログします。

deviseのgemを追記します。

・
・
・
gem 'devise'

バンドルインストールします。

$bundle install

デバイスをインストールします。

$rails generate devise:install

設定があるか確認します。

config/environments/development.rb


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

page#indexを追記します。

config/routes.rb
Rails.application.routes.draw do
root to: "page#index"


end

以下を追記します。

app/views/layouts/application.html.erb

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

Viewをインストールします。

$ rails g devise:views

以下が作られます。

app/views/devise/unlocks/new.html.erb
app/views/devise/shared/_links.html.erb
app/views/devise/shared/_error_messages.html.erb
app/views/devise/sessions/new.html.erb
app/views/devise/registrations/new.html.erb
app/views/devise/registrations/edit.html.erb
app/views/devise/passwords/new.html.erb
app/views/devise/passwords/edit.html.erb
app/views/devise/mailer/unlock_instructions.html.erb
app/views/devise/mailer/reset_password_instructions.html.erb
app/views/devise/mailer/password_change.html.erb
app/views/devise/mailer/email_changed.html.erb
app/views/devise/mailer/confirmation_instructions.html.erb
app/views/devise/confirmations/new.html.erb

モデルを作成します。
今回はUserモデルを作ります。

$ rails g devise user

以下モデルが作られます。

app/models/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
end

以下が同時に作られます。

config/application.rb
config.i18n.default_locale = :ja

以下も作られます。

config/routes.rb
ails.application.routes.draw do
devise_for :users


end

モデル作成後に、DBに反映します。

rails db:migrate

まだpage#indexのViewがないので作ります。

$ rails g controller Pages index

余談ですが、routes.rbにスコープを作ることでPathを変更できます。

routes.rb
  devise_scope :user do
    get 'login', to: 'devise/sessions#new'
    post 'login', to: 'devise/sessions/#create'
    delete 'logout', to: 'devise/sessions#destroy' 
  end

これにより、
http://localhost:3000/login
にアクセスしたときに、ログインページが表示されます。

もちろんデフォルトの/users/sign_inでもログインページが表示されるので必要であれば削除しておきましょう。

routes.rb
 devise_for :users, skip: [:sessions]

デバイスの設定は完了です。

cancancanのインストール

次にcancancanをインストールしていきます。
これは認可と言って、ユーザによって、
アクセス権を付与するという意味になります。
システム管理者と一般ユーザの違いです。

gem 'cancancan'

バンドルインストールします。

$bundle install

Abilityクラスが作成されます。

rails g cancan:ability

Abilityクラスのデフォルトです。

class Ability
  include CanCan::Ability

  def initialize(user)
    # Define abilities for the passed in user here. For example:
    #
    #   user ||= User.new # guest user (not logged in)
    #   if user.admin?
    #     can :manage, :all
    #   else
    #     can :read, :all
    #   end
    #
    # The first argument to `can` is the action you are giving the user
    # permission to do.
    # If you pass :manage it will apply to every action. Other common actions
    # here are :read, :create, :update and :destroy.
    #
    # The second argument is the resource the user can perform the action on.
    # If you pass :all it will apply to every resource. Otherwise pass a Ruby
    # class of the resource.
    #
    # The third argument is an optional hash of conditions to further filter the
    # objects.
    # For example, here the user can only update published articles.
    #
    #   can :update, Article, :published => true
    #
    # See the wiki for details:
    # https://github.com/CanCanCommunity/cancancan/wiki/Defining-Abilities
  end
end

以下に変更します。

# frozen_string_literal: true

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new
    can :read,  :all

    if user.admin? 
      can :manage,  :all

    end



    # Define abilities for the passed in user here. For example:
    #
    #   user ||= User.new # guest user (not logged in)
    #   if user.admin?
    #     can :manage, :all
    #   else
    #     can :read, :all
    #   end
    #
    # The first argument to `can` is the action you are giving the user
    # permission to do.
    # If you pass :manage it will apply to every action. Other common actions
    # here are :read, :create, :update and :destroy.
    #
    # The second argument is the resource the user can perform the action on.
    # If you pass :all it will apply to every resource. Otherwise pass a Ruby
    # class of the resource.
    #
    # The third argument is an optional hash of conditions to further filter the
    # objects.
    # For example, here the user can only update published articles.
    #
    #   can :update, Article, :published => true
    #
    # See the wiki for details:
    # https://github.com/CanCanCommunity/cancancan/wiki/Defining-Abilities
  end
end

user ||= User.new
上記がないとゲストユーザで操作しているときに、エラーになりました。

if user.admin? ←adminって何?と聞かれました。

def initialize(user)
user ||= User.new
can :read, :all
Abilityモデルが呼ばれたときに
初期値としてログインしていれば、そのユーザを変数に入れ、ログインしていなければゲストユーザが変数に代入されます。
そして、ユーザ変数に対して、read権限を付与するという意味となる。全てのユーザがread権限があるということです。

read権限というのは、CRUDに紐づいている訳ではないので注意しましょう。
ページが読めるということであり、getができるという意味ではないし、createメソッドとかも別にプログラムすればできます。

if user.admin? 
  can :manage,  :all

こちらはUserモデルに作成したadminカラムにtrueが入っていれば実行するプログラムです。
つまりは管理者権限を持つユーザということになります。

Page#indexのビューページに以下を追加します。

app/views/pages/index.html.erb
<h1>Pages#index</h1>
<p>Find me in app/views/pages/index.html.erb</p>
  <%= link_to "削除", logout_path, method: :delete %>

<% if can?  :update, current_user %>
  <h1>update</h1>

<% end %>

<% if can? :read, current_user %>
  <h1>read</h1>
<% end %>

<% if can? :update, current_user %>
今ログインしているユーザがupdateの権限を持っていれば中身を表示します。

<% if can? :read, current_user %>
もしログインしているユーザがreadの権限を持っていれば中身を表示します。

という意味になります。

db/schema.rb
  create_table "users", force: :cascade do |t|
    t.string "email", default: "", null: false
    t.string "encrypted_password", default: "", null: false
    t.string "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.boolean "admin", default: false
    t.index ["email"], name: "index_users_on_email", unique: true
    t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
  end

上記でadminってUserモデルにないけどどうするの?ってなるかと思うが、
追加することとなります。

$rails g migration AddAdminToUser admin:boolean

デフォルトで以下が作成されるので
default: "false"を追加します。

ビューページでは、adminを選択するビューは作成せず、デフォルトでユーザを作成したらadmin=falseがつくようにします。
ここでは、adminは管理側で意図的に作成することとします。

db/migrate/20200522114428_add_admin_to_users.rb

class AddAdminToUsers < ActiveRecord::Migration[6.0]
  def change
    add_column :users, :admin, :boolean, default: "false"
  end
end

マイグレートします。

$rails g migrate

DBのスキーマの確認をします。

db/schema.rb
 create_table "users", force: :cascade do |t|
    t.string "email", default: "", null: false
    t.string "encrypted_password", default: "", null: false
    t.string "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.boolean "admin", default: false
    t.index ["email"], name: "index_users_on_email", unique: true
    t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
  end

http://localhost:3000/
で一般ユーザを作成しておきます。

adminユーザは、
以下の通り作成します。

$user =User.new(id: xx, email: "xxx@yyy", password: "xxxx", admin: true)

これで手続きは完了なので、
実際に一般ユーザとAdminユーザそれぞれで、
Page#indexにアクセスします。

一般ユーザはread権限のみなのでreadを表示可能です。

Adminユーザは,manage権限(全ての権限を持つ)なのでread,updateそれぞれ表示可能です。

11
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
17