🛤️

docker-compose 下で rails new して Rails6.1+deviseを試す

2020/12/26に公開
2

TL;DR

https://github.com/heartcombo/devise

今回やること、やらないこと

  • やること
    • docker-compose を使って Rails コンテナと MySQL コンテナを用意する
    • Rails に devise を導入して email アドレスによる認証認可を構築
    • devise の日本語化をする
    • letter_opener_web を導入する
  • やらないこと
    • devise のビューとコントローラーのカスタマイズ
    • OmniAuth を導入してSNS認証などを追加する

docker-compose の準備

以下記事とほぼ同じです

サクッとやっていきましょう。

cd myapp
mkdir -p forDocker/mysql/conf.d/
touch forDocker/mysql/conf.d/mysql.cnf
mkdir -p forDocker/rails/
touch forDocker/rails/entrypoint.sh
touch Dockerfile
touch docker-compose.yml
forDocker/mysql/conf.d/mysql.cnf
[mysqld]
default_authentication_plugin = mysql_native_password
skip-host-cache
skip-name-resolve

character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
init-connect = SET NAMES utf8mb4
skip-character-set-client-handshake

[client]
default-character-set = utf8mb4

[mysqldump]
default-character-set = utf8mb4

[mysql]
default-character-set = utf8mb4
forDocker/rails/entrypoint.sh
#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /app/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"
Dockerfile
FROM ruby:2.6
RUN set -x && curl -sL https://deb.nodesource.com/setup_14.x | bash -

RUN set -x && curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
    echo 'deb http://dl.yarnpkg.com/debian/ stable main' > /etc/apt/sources.list.d/yarn.list

RUN set -x && apt-get update -qq && apt-get install -yq nodejs yarn vim default-mysql-client

RUN mkdir /app
WORKDIR /app
# ※ここのコメントはあとで外す
# COPY Gemfile /app/Gemfile
# COPY Gemfile.lock /app/Gemfile.lock
# RUN bundle install
COPY . /app

# Add a script to be executed every time the container starts.
COPY ./forDocker/rails/entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# Start the main process.
# ※ここのコメントはあとで外す
# CMD ["rails", "server", "-b", "0.0.0.0"]
docker-compose.yml
version: '3.7'

services:
  app:
    container_name: app
    build: .
    tty: true
    stdin_open: true
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/app
    ports:
      - "3000:3000"
    depends_on:
      - db

  db:
    image: mysql:8.0
    container_name: db
    restart: always
    volumes:
      - ./forDocker/mysql/conf.d:/etc/mysql/conf.d
      - dbvol:/var/lib/mysql
    ports:
      - "3306:3306"
    environment:
      MYSQL_ALLOW_EMPTY_PASSWORD: 1
      TZ: "Asia/Tokyo"

volumes:
  dbvol:

bundle init して rails new する

ここから先はこの後の docker-compose run --rm --service-ports app bash
appコンテナに入ったままコマンドを実行します
(設定ファイルの編集はvimでも、作業ディレクトリをVSCodeで開いてでもなんででも大丈夫です)

docker-compose run --rm --service-ports app bash
bundle init

Gemfile を開いて

Gemfile
# gem 'rails' ここを
gem 'rails', '~> 6.1.0' # こう変える

次に bundle install をします。
--path vendor/bundle はなくても良いと思います。
--path vendor/bundle をなくしたときは、以下のコマンドで bundle exec としている部分は
bundle exec なしで実行してください。

bundle install --path vendor/bundle --jobs=4
bundle exec rails new . -B -S -T -J -d mysql --force

devise のセットアップとは関係ないですが simpacker を入れておきます。
再度 Gemfile を開いて

Gemfile
...(前略)
group :development do
    gem "simpacker"  # group :development do 配下にこれを追記
...(後略)

追記したらまたコンソールに戻って

bundle install
bundle exec rails simpacker:install
...
Simpacker successfully installed 🎉 🍰

webpack も邪魔なので消しときましょう。

package.json
{
  "private": true,
  "devDependencies": {
  }
}

またコンソールに戻って

# rails simpacker:install では npm で node_modules が入るので消して yarn する
rm -rf node_modules/
rm package-lock.json
rm webpack.config.js
yarn install

ここまで終わったら次は Rails アプリケーションの準備を整えましょう
config/database.yml を編集します。

config/database.yml
...(前略)
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  url: mysql2://root:@db:3306
  # username: root
  # password:
  # host: localhost
...(後略)

config/database.yml の編集を行ったら、データベースの準備をしてrailsを起動してみます。

bundle exec rails db:create
bundle exec rails db:migrate
bundle exec rails s -b "0.0.0.0"

http://localhost:3000/ でいつものアレが出ましたでしょうか。
OKですね。Ctrl+c でサーバを閉じましょう。

devise を導入する

Gemfile に以下を追加。
ついでに日本語化に必要な gem も入れちゃいましょう。

Gemfile
gem 'devise'
gem 'devise-i18n'

group :development do
  gem 'letter_opener_web' # これも追加しときましょう。メール送信後の確認が簡単になります
end

Gemfile を編集したら appコンテナ の
ターミナルに戻って作業を進めます。

bundle install
bundle exec rails g devise:install

bundle exec rails g devise:install すると
以下のように手作業での導入方法が表示されますね。

Running via Spring preloader in process 10589
      create  config/initializers/devise.rb
      create  config/locales/devise.en.yml
===============================================================================

Depending on your application's configuration some manual setup may be required:

  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.

     * Required for all applications. *

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

       root to: "home#index"
     
     * Not required for API-only Applications *

  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>

     * Not required for API-only Applications *

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

       rails g devise:views
       
     * Not required *

===============================================================================

開発環境用のメール送信の設定を行う

config/environments/development.rb に以下を追記します。
どこでも良いですが私はこの辺に追記します。

config/environments/development.rb
...(前略)
  # Store uploaded files on the local file system (see config/storage.yml for options).
  config.active_storage.service = :local

  # ----- ここを追記 -----
  # Devise mailer setting
  config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
  config.action_mailer.delivery_method = :letter_opener_web
  # ----- ここまで -----

  # Don't care if the mailer can't send.
  config.action_mailer.raise_delivery_errors = false
...(後略)

root_url となる View を作成する

今回は home にしましょう。

bundle exec rails g controller Home index show
Running via Spring preloader in process 10675
      create  app/controllers/home_controller.rb
       route  get 'home/index'
get 'home/show'
      invoke  erb
      create    app/views/home
      create    app/views/home/index.html.erb
      create    app/views/home/show.html.erb
      invoke  helper
      create    app/helpers/home_helper.rb
      invoke  assets
      invoke    css
      create      app/assets/stylesheets/home.css
config/routes.rb
Rails.application.routes.draw do
  get 'home/index'
  get 'home/show'

  root to: "home#index"
  
  ## 開発環境用letter_opener
  mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development?
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end

app/views/layouts/application.html.erb にメッセージ追加

app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>App</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag 'application', media: 'all' %>
  </head>

  <body>
    <header style="margin-top:30px;">
      <nav>
        <!-- user_signed_in? はユーザがログインしているか調べる devise の Helper メソッド -->
        <% if user_signed_in? %> 
          <!-- current_user は現在ログインしているUserオブジェクトを返す devise の Helper メソッド -->
          <!-- *_path はUserモデルを作成したときに、deviseにより自動で作成されてますので、rake routes で確認できます -->
          Logged in as <strong><%= current_user.email %></strong>.
          <%= link_to 'プロフィール変更', edit_user_registration_path %> |
          <%= link_to "ログアウト", destroy_user_session_path %>
        <% else %>
          <%= link_to "サインアップ", new_user_registration_path %> |
          <%= link_to "ログイン", new_user_session_path %>
        <% end %>
      </nav>
    </header>

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

    <%= yield %>
  </body>
</html>

config/initializers/devise.rb を少し編集しておきます

config/initializers/devise.rb
  # The default HTTP method used to sign out a resource. Default is :delete.
  config.sign_out_via = :get # ここを :delete から :get に編集

認証認可用の User モデルを作成

また appコンテナ の
ターミナルに戻って作業を進めます。

bundle exec rails g devise User
Running via Spring preloader in process 10707
      invoke  active_record
      create    db/migrate/20201226101859_devise_create_users.rb
      create    app/models/user.rb
      insert    app/models/user.rb
       route  devise_for :users

生成された migration ファイルのコメントを外して全部入りモリモリでいきましょう。
(migration ファイルのファイル名は各々変わると思うので rails g devise User した時の出力などを見てみてください)

db/migrate/20201226101859_devise_create_users.rb
# frozen_string_literal: true

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

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at

      ## Rememberable
      t.datetime :remember_created_at

      ## Trackable
      t.integer  :sign_in_count, default: 0, null: false
      t.datetime :current_sign_in_at
      t.datetime :last_sign_in_at
      t.string   :current_sign_in_ip
      t.string   :last_sign_in_ip

      ## Confirmable
      t.string   :confirmation_token
      t.datetime :confirmed_at
      t.datetime :confirmation_sent_at
      t.string   :unconfirmed_email # Only if using reconfirmable

      ## Lockable
      t.integer  :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
      t.string   :unlock_token # Only if unlock strategy is :email or :both
      t.datetime :locked_at

      t.timestamps null: false
    end

    add_index :users, :email,                unique: true
    add_index :users, :reset_password_token, unique: true
    add_index :users, :confirmation_token,   unique: true
    add_index :users, :unlock_token,         unique: true
  end
end

app/models/user.rb も編集しておきます。

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,
         :trackable, :confirmable, :lockable, :timeoutable
end

編集し終わったらまた appコンテナ のターミナルに戻って migration を実行しましょう。

bundle exec rails db:migrate

終わったら Rails サーバーを起動して動作確認します。

bundle exec rails s -b "0.0.0.0"

http://localhost:3000/ にアクセスして確認。


「サインアップ」をクリックして必要情報を入れ、「Sign up]ボタンを押す


http://localhost:3000/letter_opener にアクセスすると認証用メールが確認できるので
「Confirm my account」のリンクを実行すると confirm が実行される


「ログイン」からログインしてみる

「ログアウト」からログアウトできます。


良い感じですね! 簡単!

devise で表示する view を日本語化する

また appコンテナ の ターミナルに戻って作業を進めます。

bundle exec rails g devise:views:locale ja

config/application.rb を編集します。

config/application.rb
require_relative "boot"

require "rails"
# Pick the frameworks you want:
require "active_model/railtie"
require "active_job/railtie"
require "active_record/railtie"
require "active_storage/engine"
require "action_controller/railtie"
require "action_mailer/railtie"
require "action_mailbox/engine"
require "action_text/engine"
require "action_view/railtie"
require "action_cable/engine"
# require "sprockets/railtie"
# require "rails/test_unit/railtie"

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module App
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 6.1

    # ----- ここを追記 -----
    # Devise i18n japanese
    config.i18n.default_locale = :ja
    # ----- ここまで -----

    # Configuration for the application, engines, and railties goes here.
    #
    # These settings can be overridden in specific environments using the files
    # in config/environments, which are processed later.
    #
    # config.time_zone = "Central Time (US & Canada)"
    # config.eager_load_paths << Rails.root.join("extras")

    # Don't generate system test files.
    config.generators.system_tests = nil
  end
end

終わったら Rails サーバーを起動して動作確認します。

bundle exec rails s -b "0.0.0.0"

http://localhost:3000/ にアクセスして確認。「サインアップ」をクリックすると

日本語化できてますね!オッケー!!
今回はここまでです。おつかれさまでした!

今回のリポジトリはこちらです。
https://github.com/JUNKI555/rails_authentication_practice01

参考

Discussion

たくみんたくみん

deviseインストールの際の
bundle install
rails g devise:install
bundle exec rails g devise:install

のrails g devise:installの部分は不要っぽいです!
/vendorにRailsをインストールしない際は、bundle exec不要だと最初で明言しているので、わかりづらくなってしまうかなと思いました

それとHomeコントローラー作成の際にはbundle execが抜けてしまっているので、細かい部分ですが指摘させていただきます

北山淳也北山淳也

@takumin0423 さん
ご指摘ありがとうございます!修正しました 👍