Ruby on Railsを始めるときに役に立ったメモ

 Ruby on Rails、そもそもRubyを触ってみたかったので、過去にPHPのLaravelで実装したCMSを移植してみようと思いました。そのときに役に立ったメモを備忘録として残しておきます。

  1. 前提環境
  2. 新規プロジェクト作成
  3. .github/workflows/ci.ymlファイルが実行されるように修正
  4. envファイル導入
  5. 開発環境でのメール確認
  6. 認証機能導入
    1. 一般ユーザーのモデルを作成
    2. 追加したカラムをユーザー登録時と更新時に含めるようにする
    3. (任意)confirmable機能を有効にした場合、ユーザー登録後の遷移先をメール再送信画面に設定することもできる
    4. devise用のアラートを受け取るように以下のタグを共通テンプレートに追加する
    5. ログイン関係のリンクを共通テンプレートに追加する
    6. トップページを作成する
    7. 一般ユーザーはログインしないと公開側のページにアクセスできないようにする
    8. devise日本語化
  7. 日本語化
    1. 入力フォーム項目の日本語化
  8. モデルを作成する
    1. 外部キーがあるテーブルのモデルを生成する
  9. Bootstrapの導入
    1. Gemgileに以下2つのgemを追加
    2. dartsassのインストール
    3. app/assets/stylesheets/application.scssに以下のコードを追加。(application.cssファイルは不要)
    4. javascriptの設定
      1. config/importmap.rbに以下のコードを追記(位置はどこでも良い)
      2. app/javascript/application.jsに以下のコードを追記
    5. 開発環境でscssが反映されるようにする
      1. Procfile.devの書き換え
  10. adminディレクトリ以下にコントローラーやビューを生成する
  11. 管理者機能を実装する
    1. 管理者モデルを作成する
    2. ログインIDとパスワードでログインできるようにする
    3. 管理者用の定数ファイルを作成する
    4. ログインID用のバリデーションを追加する
    5. managersテーブルにlogin_idカラムを追加する
    6. 管理者情報のシードファイルを作成する
    7. シードファイルをDBに流し込む
    8. 管理者用のログイン画面を作成する
    9. 管理者登録画面へのアクセスを禁じる
    10. 管理者ログイン後とログアウト後のリダイレクト先を設定する
    11. application_controller.rbを継承した管理者用基幹コントローラーを作成
    12. 管理者情報を更新した後のリダイレクト先を指定する
    13. 管理者情報変更画面にログインIDの入力フォームを追加
    14. 管理者情報変更処理にメールアドレスを含むようにする
    15. 管理者用ページのトップページを作成する
  12. 中間テーブルの作成

前提環境

  • Windows11
  • WSL2
  • Ubuntu 24.04.1 LTS
  • Ruby 3.3.8
  • Rails 8.0.2
  • MySQL8.4.3

新規プロジェクト作成

rails new アプリケーション名 --database=mysql --skip-hotwire

 今回はMySQLを使うので、--database=mysql を指定します。また、Hotwire は導入しないのでスキップしておきます。

.github/workflows/ci.ymlファイルが実行されるように修正

 .github/workflows/ci.yml は GitHub Actions 用の設定ファイルで、リポジトリの継続的インテグレーション(CI: Continuous Integration)処理を自動化するレシピです。簡単に言えば、GitHub 上でコードを push / pull request したときに実行する自動テストやビルド手順を記述するファイルです。ですが、私の環境では権限の問題などで上手く動作しなかったので修正します。

  • scan_ruby
# run: bin/brakeman --no-pager
run: bundle exec brakeman --no-pager
  • scan_js
- name: Make importmap script executable
  run: chmod +x bin/importmap

# 上に追加しておく
- name: Scan for security vulnerabilities in JavaScript dependencies
  run: bin/importmap audit
  • lint
#run: bin/rubocop -f github
run: bundle exec rubocop -f github
  • test
# - name: Run testsの前に
- name: Make bin scripts executable
  run: chmod +x bin/*

- name: Set up database.yml for CI
  run: cp config/database.yml.ci config/database.yml

 config\database.yml.ciにテスト環境のDB情報を記述します。

test:
  adapter: mysql2
  encoding: utf8
  collation: utf8_general_ci
  pool: 5
  username: root
  password:
  host: 127.0.0.1
  database: test環境のDB名

envファイル導入

gem "dotenv-rails"
bundle install

 アプリケーションのルートディレクトリに .env ファイル作成します。

# 現在の環境
RAILS_ENV=development
# MySQLで作成したユーザー名
DATABASE_USER = 'MySQLで作成したユーザー名'
# ユーザーのパスワード
DATABASE_PASSWORD = 'ユーザーのパスワード'
# ホスト名
DATABASE_HOST = 'localhost' 
# 開発環境のデータベース名
DATABASE_NAME = '開発環境のデータベース名'
# 管理者パスワード 
MANAGER1_PASSWORD = test1test1
MANAGER2_PASSWORD = test2test2
# アプリケーション名
APP_NAME = アプリケーション名
# メールアドレス
MAIL_FROM_ADDRESS="hello@example.com"

 database.yml に .env ファイルの接続情報を記載します。

default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: <%= ENV['DATABASE_USER'] %>
  password: <%= ENV['DATABASE_PASSWORD'] %>
  host: <%= ENV['DATABASE_HOST'] %>
  socket: /var/run/mysqld/mysqld.sock

development:
  <<: *default
  database: <%= ENV['DATABASE_NAME'] %>
test:
  <<: *default
  database: <%= ENV['DATABASE_NAME'] %>_test

開発環境でのメール確認

 認証機能として devise を導入しますがメールでのアカウント確認処理も入っているので、ブラウザで /letter_opener にアクセスして開発環境で送信されるメールの確認をするために導入します。

group :development do
  gem "letter_opener_web"
end
bundle install
config.action_mailer.delivery_method = :letter_opener_web
config.action_mailer.perform_deliveries = true

認証機能導入

gem "devise"
bundle install
rails generate devise:install

一般ユーザーのモデルを作成

rails generate devise User

 ユーザー名カラムをユーザーモデルに追加します。分かりやすい命名規則のマイグレーションファイル名を心がけましょう。

rails generate migration AddNameToUsers name:string:uniq

 定数ファイルの作成を作成します。あらかじめ app ディレクトリ内に constants フォルダを作成しておきます。

module UserConstants
  NAME_LENGTH = 20
end

 作成したマイグレーションファイルに定数を導入して追記する。

class AddNameToUsers < ActiveRecord::Migration[8.0]
  def change
    add_column :users, :name, :string, limit: UserConstants::NAME_LENGTH_MAX, null: false, default: ""
    add_index :users, :name, unique: true
  end
end

 生成された User モデルに機能とバリデーションを追加します。
 ※有効にした機能に合わせて users テーブルのコメントアウトされているカラムを有効にしておくことを忘れないように。

devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable,
         :confirmable, :timeoutable

validates :name,
  presence: true,
  length: { maximum: UserConstants::NAME_LENGTH_MAX, allow_blank: true },
  uniqueness: { allow_blank: true },
  unless: :devise_password_reset?

private

def devise_password_reset?
  reset_password_token.present?
end

 マイグレーションを実行します。

rails db:migrate

追加したカラムをユーザー登録時と更新時に含めるようにする

 deviseのコントローラーを生成します。

rails generate devise:controllers users

 生成するコントローラーを指定することもできます。

rails generate devise:controllers users -c=registrations

 追加したカラムをユーザー登録時と更新時に含めるようにします。

before_action :configure_sign_up_params, only: [:create]
before_action :configure_account_update_params, only: [:update]

protected
def configure_sign_up_params
  devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
end
def configure_account_update_params
  devise_parameter_sanitizer.permit(:account_update, keys: [:name])
end

 追加したカラムに対応する入力フォームをユーザー登録時と更新時のビューに追加する

rails generate devise:views users

 ※ビューもコントローラーと同じで -v registrations とパラメーターを指定することでregistrations だけ生成することができる。

(任意)confirmable機能を有効にした場合、ユーザー登録後の遷移先をメール再送信画面に設定することもできる

protected
def after_inactive_sign_up_path_for(resource)
  new_user_confirmation_path(resource)
end

devise用のアラートを受け取るように以下のタグを共通テンプレートに追加する

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

ログイン関係のリンクを共通テンプレートに追加する

<header>
    <% if user_signed_in? %>
    <li>
        <%= link_to "アカウント情報更新", edit_user_registration_path %>
    </li>
    <li>
        <%= button_to "ログアウト", destroy_user_session_path, method: :delete %>
    </li>
    <% else %>
    <li>
        <%= link_to "新規登録", new_user_registration_path %>
    </li>
    <li>
        <%= link_to "ログイン", new_user_session_path %>
    </li>
    <% end %>
</header>

トップページを作成する

 ログインした後に表示されるTopController を生成します。(ルートには自動的に登録されている)パラメーターを指定することで index アクションのみのコントローラーを生成することができます。

rails g controller top index
get "top/index"
root "top#index"

 ※scaffold_controllerコマンドでも、アクションとビューの種類を限定して生成することもできます。こちらは既存モデル(例:Post)に対する RESTful な CRUD 画面を効率よく作ることができます。

rails g scaffold_controller Post index show --model-name=Post

一般ユーザーはログインしないと公開側のページにアクセスできないようにする

class ApplicationController < ActionController::Base
  before_action :authenticate_user!
end

devise日本語化

gem "devise-i18n"
bundle install

 config/lacalesディレクトリに、devise.ja.ymlファイルを作成し以下を記入します。https://github.com/tigrish/devise-i18n/blob/master/rails/locales/ja.yml参照
※管理者用の入力フォームやモデルも追加しておくこと。

日本語化

gem "rails-i18n"
bundle install
config.i18n.default_locale = :ja
config.i18n.load_path+=Dir[Rails.root.join('config','locales','**','*.yml').to_s]

 https://github.com/svenfuchs/rails-i18n/blob/master/rails/locale/ja.yml参照

入力フォーム項目の日本語化

ja:
  activerecord:
    models:
      news: お知らせ
      first_category: 大カテゴリ
      second_category: 中カテゴリ
      tag: タグ
      product: 製品情報
      medium: メディア
      contact: お問い合わせ
    attributes:
      news:
        title: タイトル
        link_flg: リンク設定
        url: URL
        overview: 概要
        release_date: 公開日
        release_flg: 表示設定

モデルを作成する

rails generate model Tag name:string:uniq

外部キーがあるテーブルのモデルを生成する

rails generate model SecondCategory name:string first_category:references

Bootstrapの導入

Gemgileに以下2つのgemを追加

gem "dartsass-rails"
gem "bootstrap", "~> 5.3.3"
bundle install

dartsassのインストール

rails dartsass:install

app/assets/stylesheets/application.scssに以下のコードを追加。(application.cssファイルは不要)

@import "bootstrap";

javascriptの設定

config/importmap.rbに以下のコードを追記(位置はどこでも良い)

pin "bootstrap", to: "bootstrap.min.js", preload: true
pin "@popperjs/core", to: "popper.js", preload: true

app/javascript/application.jsに以下のコードを追記

import "@popperjs/core"
import "bootstrap"

開発環境でscssが反映されるようにする

Procfile.devの書き換え

  • Procfile.dev のファイル名を Procfile に変更
  • 中身の修正(bin/を削除)
- web: bin/rails server -p 3000
+ web: rails server -p 3000
- css: bin/rails dartsass:watch
+ css: rails dartsass:watch

 rails sの代わりに以下のコマンドで実行(foremanを使って実行)

foreman start -f Procfile
or
foreman start

 参考URL:https://qiita.com/arata0520/items/9e34b96f035dce75f6cd

adminディレクトリ以下にコントローラーやビューを生成する

rails generate scaffold_controller Admin::Tag name:string:uniq --model-name=Tag --system-tests-dir=test/system/admin

 rails generate scaffold_controller コマンドは、指定したモデルに対応する “CRUD(一覧・詳細・新規・編集・削除)処理用のコントローラとビュー” を一括生成するジェネレータです。
 ※–system-tests-dir=test/system/admin と指定しても上手くadminディレクトリに生成されないので、adminディレクトリを自作しその中にテストファイルを移します。クラス名にAdmin::を追加するのを忘れないこと。

管理者機能を実装する

管理者モデルを作成する

rails g devise Manager 

ログインIDとパスワードでログインできるようにする

class Manager < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :validatable, authentication_keys: [ :login_id ]
end

管理者用の定数ファイルを作成する

module ManagerConstants
  LOGIN_ID_LENGTH_MIN = 8
  LOGIN_ID_LENGTH_MAX = 20
end

ログインID用のバリデーションを追加する

class Manager < ApplicationRecord
  validates :login_id,
    presence: true,
    length: { minimum: ManagerConstants::LOGIN_ID_LENGTH_MIN, maximum: ManagerConstants::LOGIN_ID_LENGTH_MAX, allow_blank: true },
    uniqueness: { allow_blank: true }
end

 ※deviseで有効にした機能と関係するカラムをマイグレーションファイル内で有効もしくは無効にすること。

managersテーブルにlogin_idカラムを追加する

rails generate migration add_login_id_to_managers login_id:string:uniq
class AddLoginIdToManagers < ActiveRecord::Migration[8.0]
  def change
    add_column :managers, :login_id, :string, limit: ManagerConstants::LOGIN_ID_LENGTH_MAX, null: false, default: ""
    add_index :managers, :login_id, unique: true
  end
end
rails db:migrate

管理者情報のシードファイルを作成する

Manager.find_or_create_by!(login_id: 'test1test1') do |manager|
  manager.email = 'test1@test.co.jp'
  manager.password = ENV.fetch('MANAGER1_PASSWORD')
  manager.password_confirmation = ENV.fetch('MANAGER1_PASSWORD')
end

Manager.find_or_create_by!(login_id: 'test2test2') do |manager|
  manager.email = 'test2@test.co.jp'
  manager.password = ENV.fetch('MANAGER2_PASSWORD')
  manager.password_confirmation = ENV.fetch('MANAGER2_PASSWORD')
end

シードファイルをDBに流し込む

rails db:seed

管理者用のログイン画面を作成する

rails g devise:controllers admin/managers -c=sessions registrations

 config/routes.rb にルートを追加します。

namespace :admin do
  devise_for :managers,
    controllers: {
      sessions:      "admin/managers/sessions",
      registrations:     "admin/managers/registrations"
      # :registerable を使わないなら registrations は外す
    },
  resources :tags
end

管理者登録画面へのアクセスを禁じる

 私が実装するCMSでは管理者は登録画面が存在せず、シードファイルで流し込まれた管理者情報しか使えないので、管理者登録画面に関わるアクションのアクセスを禁止しておきます。

# GET /resource/sign_up
def new
  redirect_to admin_root_path, alert: "新規登録は許可されていません。"
end

# POST /resource
def create
  redirect_to admin_root_path, alert: "新規登録は許可されていません。"
end

管理者ログイン後とログアウト後のリダイレクト先を設定する

protected

def after_sign_in_path_for(resource)
  admin_root_path(resource)
end

def after_sign_out_path_for(resource_or_scope)
  new_admin_manager_session_path(resource)
end

application_controller.rbを継承した管理者用基幹コントローラーを作成

class Admin::ApplicationController < ApplicationController
  skip_before_action :authenticate_user!
  before_action :authenticate_admin_manager!
end

管理者情報を更新した後のリダイレクト先を指定する

def after_update_path_for(resource)
  sign_in_after_change_password? ? admin_root_path(resource) : new_admin_manager_session_path(resource_name)
end

管理者情報変更画面にログインIDの入力フォームを追加

rails g devise:views admin/managers -v sessions registrations

管理者情報変更処理にメールアドレスを含むようにする

before_action :configure_account_update_params, only: [:update]

protected
def configure_account_update_params
  devise_parameter_sanitizer.permit(:account_update, keys: [:login_id, :email])
end

 管理者ログイン画面の入力フォームをメールアドレスからログインIDに変更する

管理者用ページのトップページを作成する

rails g controller admin/top index

 ※Admin::ApplicationControllerを継承するように手動で修正しておくこと

中間テーブルの作成

 HABTM(has_and_belongs_to_many)の中間テーブルは アルファベット順で複数形 の組み合わせが推奨されます。productsテーブルとtagsテーブルの中間テーブルを作成する場合:products_tags(p < t なので)

rails g migration CreateJoinTableProductsTags products tags

コメント

タイトルとURLをコピーしました