Ruby on Rails、そもそもRubyを触ってみたかったので、過去にPHPのLaravelで実装したCMSを移植してみようと思いました。そのときに役に立ったメモを備忘録として残しておきます。
- 前提環境
- 新規プロジェクト作成
- .github/workflows/ci.ymlファイルが実行されるように修正
- envファイル導入
- 開発環境でのメール確認
- 認証機能導入
- 日本語化
- モデルを作成する
- Bootstrapの導入
- adminディレクトリ以下にコントローラーやビューを生成する
- 管理者機能を実装する
- 管理者モデルを作成する
- ログインIDとパスワードでログインできるようにする
- 管理者用の定数ファイルを作成する
- ログインID用のバリデーションを追加する
- managersテーブルにlogin_idカラムを追加する
- 管理者情報のシードファイルを作成する
- シードファイルをDBに流し込む
- 管理者用のログイン画面を作成する
- 管理者登録画面へのアクセスを禁じる
- 管理者ログイン後とログアウト後のリダイレクト先を設定する
- application_controller.rbを継承した管理者用基幹コントローラーを作成
- 管理者情報を更新した後のリダイレクト先を指定する
- 管理者情報変更画面にログインIDの入力フォームを追加
- 管理者情報変更処理にメールアドレスを含むようにする
- 管理者用ページのトップページを作成する
- 中間テーブルの作成
前提環境
- 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
コメント