##はじめに
deviseを使用してUserモデル(認証)を作成後して
cancancanを追加して認可をできるようにしました。
その過程を備忘録としてログします。
deviseのgemを追記します。
・
・
・
gem 'devise'
バンドルインストールします。
$bundle install
デバイスをインストールします。
$rails generate devise:install
設定があるか確認します。
・
・
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
page#indexを追記します。
Rails.application.routes.draw do
root to: "page#index"
・
・
end
以下を追記します。
<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
以下モデルが作られます。
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.i18n.default_locale = :ja
以下も作られます。
ails.application.routes.draw do
devise_for :users
・
・
end
モデル作成後に、DBに反映します。
rails db:migrate
まだpage#indexのViewがないので作ります。
$ rails g controller Pages index
余談ですが、routes.rbにスコープを作ることでPathを変更できます。
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でもログインページが表示されるので必要であれば削除しておきましょう。
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のビューページに以下を追加します。
<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の権限を持っていれば中身を表示します。
という意味になります。
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は管理側で意図的に作成することとします。
class AddAdminToUsers < ActiveRecord::Migration[6.0]
def change
add_column :users, :admin, :boolean, default: "false"
end
end
マイグレートします。
$rails g migrate
DBのスキーマの確認をします。
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それぞれ表示可能です。