devise、cancanと連携して管理者ユーザーにのみRailsAdminを公開するには


RailsAdmin は、Railsで最も良く使われている管理画面のgemで、Modelのデータを管理する画面を自動生成してくれます。
RailsAdminを利用すれば、MySQLAdmin的なツールを使わずに安全にデータのメンテナンスができるようになります。

RailsAdmin は認証に devisesocery、認可(アクセスコントロール)に cancan と連携することができます。

Railsプロジェクトの新規作成から RailsAdmin および devise、cancan をセットアップするまでの手順をまとめました。
Rubyは 2.0.0、Railsは、4.0.2 で試しています。

確認用プロジェクト作成

プロジェクトを作成して適当にモデルを一つ追加しておきます。

$ rails new rails_admin
$ cd rails_admin
$ bundle install --path vendor/bundle
$ rails g scaffold post title:string message:text
$ rake db:migrate

RailsAdminのインストール

インストール手順は、Githubの READMEのInstallation に記述されている通り進めます。

1. Bundle the gem
2. Run rails g rails_admin:install
3. Provide a namespace for the routes when asked
4. Start a server rails s and administer your data at /admin. (if you chose default namespace: /admin)

Gemfile に rails_admin を追加して bundle install した後、インストールを実行します。

# Gemfile
gem 'rails_admin'
$ bundle install
...
Installing font-awesome-rails (4.0.3.1)
...
Installing haml (4.0.5)
...
Installing jquery-ui-rails (4.2.0)
...
Installing kaminari (0.15.1)
Installing mini_portile (0.5.2)
Installing nested_form (0.3.2)
Installing nokogiri (1.6.1)
Installing rack-pjax (0.7.0)
...
Installing remotipart (1.2.1)
Installing safe_yaml (1.0.1)
...
Installing rails_admin (0.6.1)
...
$ rails g rails_admin:install
           ?  Where do you want to mount rails_admin? Press <enter> for [admin] > 
       route  mount RailsAdmin::Engine => '/admin', :as => 'rails_admin'
      create  config/initializers/rails_admin.rb

管理画面のパスはデフォルトの admin で良いので、そのまま

ここまで、確認してみます。

$ bundle exec rails s

http://localhost:3000/admin/ にアクセスすると以下のような画面を確認できます。

rails_admin

deviseのセットアップ

Gemfile に devise を追加して bundle install した後、deviseのインストールと認証用モデル user を作成します。

# Gemfile
gem 'devise'
$ bundle install
...
Installing bcrypt (3.1.7)
...
Installing orm_adapter (0.5.0)
Installing warden (1.2.3)
Installing devise (3.2.4)
...
$ rails g devise:install
$ rails g devise user
$ rake db:migrate

devise自体の設定は、今回はユーザの作成と認証ができれば良いので、デフォルトのまま次に進みます。

Authentication · sferik/rails_admin Wiki を参照すると、設定は config/initializer/rails_admin.rb の Devise の箇所のコメントを外すだけです。

# config/initializers/rails_admin.rb
RailsAdmin.config do |config|

  ### Popular gems integration

  ## == Devise ==
  config.authenticate_with do
    warden.authenticate! scope: :user
  end
  config.current_user_method(&:current_user)

  ## == Cancan ==
  # config.authorize_with :cancan

ここまでの動作を確認してみます。
未認証で /admin にアクセスすると以下のように認証画面にリダイレクトされるようになりました。

rails_admin_devise

cancanのセットアップ

上記まででは、認証されたユーザーがすべて /admin にアクセスできてしまうため、さらに管理者権限を持っているユーザーのみにアクセスを制限します。

アクセス制限は、Authorization · sferik/rails_admin Wiki および CanCan · sferik/rails_admin Wiki
を参考に cancan をインストールして設定します。

# Gemfile
gem 'cancan'
$ bundle install
...
Installing cancan (1.6.10)
...
$ rails g cancan:ability
      create  app/models/ability.rb

config/initializers/rails_admin.rb の Cancan の設定のコメントを外します。

# config/initializers/rails_admin.rb
RailsAdmin.config do |config|

  ### Popular gems integration

  ## == Devise ==
  config.authenticate_with do
    warden.authenticate! scope: :user
  end
  config.current_user_method(&:current_user)

  ## == Cancan ==
  config.authorize_with :cancan

この時点で /admin にアクセスするとすべてのユーザーで403になります。

rails_admin_cancan_all_deny

次に、Userモデルに admin フラグを追加して、admin? が true の時だけ /admin にアクセスできるように修正していきます。

admin フラグを Userモデルに追加

$ rails g migration AddAdminToUser user

~~ruby

db/migrate/20140322130042_add_admin_to_user.rb

class AddAdminToUser < ActiveRecord::Migration
def change
add_column :users, :admin, :boolean, :default => false
end
end


~~~bash $ rake db:migrate

Railsコンソールで、管理者ユーザーの admin を true にセットします。

$ rails c
> user = User.find(1)
> user.update_attribute(:admin, true)

参考: ruby on rails – how to make admin users using devise and cancan? – Stack Overflow

rails generateコマンドで生成された Abilityクラスのinitializeに権限ロジックを追加します。
以下、user#admin? が true の時に rails_admin へのアクセスとすべてのモデルの管理権限を許可します。

# app/models/ability.rb
class Ability
  include CanCan::Ability

  def initialize(user)
    if user && user.admin?
      can :access, :rails_admin   # grant access to rails_admin
      can :manage, :all           # allow superadmins to do anything
    end
  end
end

initializeに渡される user は、コントローラのcurrent_userメソッドが返すオブジェクトです。
つまり、deviseを利用している場合は、何もしなくても認証用のモデル(今回は User)と連携します。

以上で、RailsAdminのダッシュボードへは、管理者権限を持つユーザーのみが利用可能になります。

,