Ruby on Rails の User 認証ライブラリである Devise を使ってみる

初めに

以下操作は WSL で実施しています。 Rails の操作ばかりなのでOSには依存しないと思いますが。 Ruby / Rails の環境は以下です。

$ ruby -v
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-linux]
$ rails -v
Rails 6.0.0

Getting Started をなぞる

インストール

Deviseをテストするために新規プロジェクト作成。 既にプロジェクトがあってそこでテストできるならここは別にやらなくてもよいです。

rails new devise_test -d postgresql
# プロジェクトの作成が完了したら移動
cd devise_test

devise を入れるために Gemfile に以下の記述を追加する。

gem 'devise'

Gemfile の内容を更新したので Bundle を利用してインストール。 bundle コマンド単体で bundle install の効果があります。

bundle

rails generate により、 devise の最低限必要な設定ファイルを生成する。

rails generate devise:install

この時に以下のファイルが生成されているはず。

create  config/initializers/devise.rb
create  config/locales/devise.en.yml

本家サイトの Getting Started によると、 これらの設定ファイルを絶対読め、と書いてあるので読みましょう。 といっても Devise の設定ファイルとLocalizationファイルなので片方は読むというほどでもない気がしますが。 まぁ何となく雰囲気だけ察する感じで。

そして、さっきのコマンドで以下のようなガイドが表示されるので対応していく。

Some setup you must do manually if you haven't yet:

  1. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:

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

     In production, :host should be set to the actual host of your application.

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root to: "home#index"

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

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

  4. You can copy Devise views (for customization) to your app by running:

       rails g devise:views

雑に日本語訳すると、

以下の設定を確認してください。

1.  環境設定ファイルにデフォルトURLオプションを設定したか確かめてください。
    例えばDevelopment環境だと以下の値を config/environments/development.rb に入れると良いでしょう。

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

    Production環境では適切な設定に替えてください。

2. config/routes.rb で root URL をちゃんと設定しているか確かめてください。例えば以下のように。

      root to: "home#index"

3. app/views/layouts/application.html.erb で flash しているか確かめてください。例えば以下のように。

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

4. DeviseのViewを以下コマンドでコピーできるので、カスタマイズしてみてください。

     rails g devise:views

ということで、各インストラクションに従ってみる。

1.にある通り上記の値を指定されたファイルの active_mailer に関する設定がされているあたりに追記。

2.の通りRoot URLを記述。

3.の通りメッセージをFlashするように修正。

4.はまぁいいか。ということでひとまず置いておきます。

モデルの作成

さて、ここで認証に使うモデルを作成しましょう。 基本的には User という名前になると思うので、ここでは User ですがどんな名前を使っても構いません。 因みに作成済みのモデルであっても特に問題はないそうです。

rails generate devise User

これにより migration ファイルが作成されるので、内容を確かめましょう。 Devise が必要に応じて機能を追加できるように migration ファイルを作成してくれているので便利ですね。

例えば User のアクティビティを追跡したいのであれば Trackable とコメントのあるあたりのプロパティのコメントを外していきます。同じく、登録時の確認などを実施するのであればConfirmable のセクションを全部コメント外しが必要になります。 これらの変更を加える際には、ファイルの下部に存在する add_index の対応する行もコメント外しするのをお忘れなく。

ここまで来たら migration しましょう。 まだ DB を作ってなかったので db:create も一緒に。

rails db:create
rails db:migrate

これにより何が作成されたかを routes コマンドで確認してみます。

$ rails routes
                  Prefix Verb   URI                            Pattern Controller#Action
        new_user_session GET    /users/sign_in(.:format)       devise/sessions#new
            user_session POST   /users/sign_in(.:format)       devise/sessions#create
    destroy_user_session DELETE /users/sign_out(.:format)      devise/sessions#destroy
       new_user_password GET    /users/password/new(.:format)  devise/passwords#new
      edit_user_password GET    /users/password/edit(.:format) devise/passwords#edit
           user_password PATCH  /users/password(.:format)      devise/passwords#update
                         PUT    /users/password(.:format)      devise/passwords#update
                         POST   /users/password(.:format)      devise/passwords#create
cancel_user_registration GET    /users/cancel(.:format)        devise/registrations#cancel
   new_user_registration GET    /users/sign_up(.:format)       devise/registrations#new
  edit_user_registration GET    /users/edit(.:format)          devise/registrations#edit
       user_registration PATCH  /users(.:format)               devise/registrations#update
                         PUT    /users(.:format)               devise/registrations#update
                         DELETE /users(.:format)               devise/registrations#destroy
                         POST   /users(.:format)               devise/registrations#create
                    root GET    /                              home#index

なんだか色々ありますが、よくよくURLを見ればログインしたりパスワード変更したりと 必要そうなものがそろっていることが分かります。

また、 Devise が最低限のレベルの View も作ってくれているのでこの段階でSignUp/SignOut可能です。 /users/sign_up にアクセスすると、登録画面が出るはずです。

適当に自分のメアドと変なパスワードで登録してみます。 メールは実際には送られません。

登録すると、セッションが作成され自動的にログインするのですが Root URL である Home を特に何も作成していないためエラー画面に遷移させられてしまいますが、 /users/edit にアクセスし直してみると、確かに自分が作成した User でログインできていることが確認できます。

ログイン状態に基づくアクセス制限

Getting Startedではこの後アクセス制限の話が出てきます。 アクセス制限をするにも今のままではアクセスするページがないのでそれを作成します。 既にページがある場合は飛ばしてください。

rails g controller home index

これで index 用の Viewを作成しました。 前述の通り Root URL に設定していたのでこれでトップページが home#index になります。

ただこれだけだとテストができないので、アクセス制限テスト用のページを作成し、 home#index からアクセスできるようにします。

中身は適当ですが、 app/views/home/index.html.erb を以下のようにしました。

<h1>Top Page</h1>

<div>
  <%= link_to('Test Page', home_test_path) %>
</div>
<div>
  <%= link_to('Login', new_user_session_path) %>
</div>
<div>
  <%= link_to('Logout', destroy_user_session_path, method: :delete) %>
</div>

これでトップページからログイン、ログアウト、テストページへのアクセスができるようになります。

つづいて、テストページを適当に作ります。 上記の例だと home_test_path とあるように、

  • HomeControllertest という関数を追加
  • app/views/home/test.html.erb というファイルを適当な内容で作成

しています。

さて、ここで home#test にアクセス制限をかけましょう。 簡単にアクセス制限をかけるには before_action :authenticate_user を利用します。 ただし、 HomeController にそのままこの before_action を付けてしまうと全部の関数に制限がかかってしまうので only: により関数を制限します。 具体的には以下のようになりました。

class HomeController < ApplicationController
  before_action :authenticate_user!, only: :test
  def index
  end

  def test
  end
end

これで rails s によりサーバを起動しアクセスし、 home#test にアクセスするとアクセス制限がかかっていることが分かります。 次にログインしてから同ページにアクセスするときちんと内容が見えます。

コメント

このブログの人気の投稿

gnuplot: グラフの色を変更する

[Linux] rsyncで進捗を確認する

gnuplotで縦線を引きたい