ログイン機能を作成する(パート3:ユーザー管理機能をもつログイン機能を実装する)
ユーザーモデルにadminフラグを追加する
ユーザーが管理者かどうかを表すフラグを追加。まずはマイグレーションファイルの雛形を作成する。
bundler exec rails g migration add_admin_to_users
マイグレーションファイルを開き、データベースの中身を定義していく。
class AddAdminToUsers < ActiveRecord::Migration[5.2]
def change
add_column :users, :admin, :boolean, default: false, null: false
end
end
そして、migrateしてuserテーブルにadminカラムを追加。
ユーザー管理するためのコントローラーを作成する
ユーザー管理のためのコントローラーを作成します。今回はadminのモジュールの中にUsersControllerというクラスを持たせるので、Admin::UserControllerという名前をつけます。※Railsではモジュール階層をコードを保存するためのディレクトリ階層に対応させているため、app/controllers/admin/users_controller.rb
といったファイルが対応する。これは管理系の機能を追加したいときに、admin::のついたコントローラーを追加していけばコードがadminディレクトリの下にまとまりわかりやすくなります。
※複数の管理系コントローラーがあるアプリケーションの場合は共通処理を持たせるために基底クラス(例: Admin::BaseController)を作り、各管理系コントローラーがそれを継承するように作るのが一般的らしい。
ここからはAdmin::UserControllerにCRUD機能を実装していきます。まずはコントローラーを作成します。
bundler exec rails g controller Admin::Users new edit show index
routesが自動で生成されたのでこれを変更していく。(config/routes.rb)
Rails.application.routes.draw do
namespace :admin do
resources :users
end
#get 'ideas/index'
#get 'ideas/show'
#get 'ideas/new'
#get 'ideas/edit'
root 'ideas#index'
resources :ideas
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
そしてコントローラーで各アクションを設定します。(app/controllers/admin/users_controller.rb)
class Admin::UsersController < ApplicationController
def new
@user = User.new
end
def create
@user = User.new(user_params)
if @user.save
redirect_to admin_users_path, notice: "ユーザーd「#{@user}」を登録しました。"
else
render :new
end
end
def edit
end
def show
end
def index
end
private
def user_params
params.require(:user).permit(:name, :email, :admin, :password, :password_confirmation)
end
end
次にviewを作成していきます。(app/views/admin/users/new.html.erb)
<div>
<h1>ユーザー登録</h1>
<%= form_with model: [:admin, @user], local: true do |f| %>
<div class="form-group">
<%= f.label :name, 'Name' %>
<%= f.text_field :name, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :email, 'Email' %>
<%= f.text_field :email, class: 'form-control' %>
</div>
<div class="form-check">
<%= f.label :admin, class: 'form-check-label' %>
<%= f.check_box :admin, class: 'form-check-input', title: 'Admin' %>
</div>
<div class="form-group">
<%= f.label :password, 'Password' %>
<%= f.password_field :password, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :password_confirmation, 'Confirm your password' %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
</div>
<div>
<%= f.submit 'Sign up', class: 'btn btn-primary' %>
</div>
<% end %>
</div>
次にバリデーションをパスワードとメールにバリデーションを追加します。(app/models/user.rb)
class User < ApplicationRecord
has_secure_password
validates :name, presence: true
validates :email, presence: true, uniqueness: true
end
rails serverを起動すると以下のように画面が表示されます。
チェックボックスの位置がおかしな場所にありますがあとで修正します。
そのほかのアクションを追加する
ここからindex, show, edit, update, destroyアクションを追加していきます。(app/controllers/admin/users_controller.rb)
def index
@users = User.all
end
def show
@user = User.find(params[:id])
end
def new
@user = User.new
end
def edit
@user = User.find(params[:id])
end
def create
@user = User.new(user_params)
if @user.save
redirect_to admin_users_path,
notice: "ユーザー「#{@user.name}」を登録しました。"
else
render :new
end
end
def update
@user = User.find(params[:id])
if @user.update(user_params)
redirect_to admin_user_path(@user),
notice: "ユーザー「#{@user.name}」を更新しました。"
else
render :new
end
end
def destroy
@user = User.find(params[:id])
@user.destroy
redirect_to admin_users_url,
notice: "ユーザー「#{@user.name}を削除しました。」"
end
private
def user_params
params.require(:user).permit(:name, :email, :admin, :password, :password_confirmation)
end
end
index画面を作成する。(app/views/admin/users/index.html.erb)
<div>
<h1>ユーザー一覧</h1>
<div>
<%= link_to 'Sign Up', new_admin_user_path,
class: 'btn btn-primary' %>
<div class="mb-3">
<table class="table table-hover">
<thead>
<tr>
<th><% t '.name' %>></th>
<th><% t '.email' %></th>
<th><% t '.admin' %></th>
<th><% t '.created_at' %></th>
<th><<% t '.updated_at' %></th>
</tr>
<tbody>
<%= @users.each do |user| %>
<tr>
<td><%= link_to user.name, [:admin, user] %></td>
<td><% user.email %><td>
<td><% user.admin? ? 'あり' : 'なし' %></td>
<td><% user.created_at %></td>
<td><% user.updated_at %></td>
<td>
<%= link_to '編集', edit_admin_user_path(user),
class: 'bot btn-primary mr-3' %>
</td>
<td>
<%= link_to '削除', [:admin, user], method: :delete, data: {confirm: "ユーザー「#{user.name}」を削除します。よろしいですか?"}, class: 'btn btn-danger' %>
</td>
</tr>
<% end %>
</tbody>
</thead>
</table>
</div>
</div>
</div>
new.html.erb
を少しいじる。(app/views/admin/users/new.html.erb)
※ちなみにこの状態でserverを起動するとpartialで指定したformファイルが存在しないためエラーが発生する。このあと追加するのでまだserverは実行しない
<h1>ユーザー登録</h1>
<div class="nav.justify-content-end">
<%= link_to 'Sing Up', admin_users_path,
class: 'nav-link' %>
<%= render partial: 'form', locals: {user: @user}%>
</div>
続いてedit.html.erb
を作成する(app/views/admin/users/edit.html.erb)
<% if user.errors.present? %>
<ul>
<div id="error_explanation">
<%= user.errors.full_messages.each do |message| %>
<li><% message %></li>
<% end %>
</div>
</ul>
<% end %>
<%= form_with model: [:admin, @user], local: true do |f| %>
<div class="form-group">
<%= f.label :name, 'Name' %>
<%= f.text_field :name, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :email, 'Email' %>
<%= f.text_field :email, class: 'form-control' %>
</div>
<div class="form-check">
<%= f.label :admin, class: 'form-check-label' %>
<%= f.check_box :admin, class: 'form-check-input', title: 'Admin' %>
</div>
<div class="form-group">
<%= f.label :password, 'Password' %>
<%= f.password_field :password, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :password_confirmation, 'Confirm your password' %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
</div>
<div>
<%= f.submit 'Sign up', class: 'btn btn-primary' %>
</div>
<% end %>
show.html.erb
を編集します。(app/views/admin/users/show.html.erb)
<div>
<h1>ユーザー詳細</h1>
<div class="nav-justify-content-end">
<%= link_to '一覧', admin_users_path, class: 'nav-link' %>
<table class="table table-hover">
<tbody>
<tr>
<th><% t '.id' %></th>
<td><% @user.id %></td>
</tr>
<tr>
<th><% t '.name' %></th>
<td><% @user.name %></td>
</tr>
<tr>
<th><% t '.email' %></th>
<td><% @user.email %></td>
</tr>
<tr>
<th><% t '.admin' %></th>
<td><% @user.admin? 'あり' : 'なし' %></td>
</tr>
<tr>
<th><% t '.created_at' %></th>
<td><% @user.created_at %></td>
</tr>
<tr>
<th><% t '.updated_at' %></th>
<td><% @user.updated_at %></td>
</tr>
</tbody>
</table>
<%= link_to '編集', edit_admin_user_path,
class: 'btn btn-primary mr-3' %>
<%= link_to '削除', [:admin, @user], method: :delete,
data: { confirm: "ユーザー「#{@user.name}」を削除します。よろしいですか?"},
class: 'btn btn-danger' %>
</div>
</div>
日本語を出力できるようにする
最後に使える言語に日本語を追加します。デフォルトでは英語が設定されているので、日本語にするための設定が必要です。
まずは新しいファイルを作成します。ファイル名はlocale.rb
とします。(config/intializers/)
ファイルの中に以下を記載。
Rails.application.config.i18n.default_locale = :ja
そしてja.yml
の中に以下をコピペします。
ja:
activerecord:
errors:
messages:
record_invalid: 'バリデーションに失敗しました: %{errors}'
restrict_dependent_destroy:
has_one: "%{record}が存在しているので削除できません"
has_many: "%{record}が存在しているので削除できません"
date:
abbr_day_names:
- 日
- 月
- 火
- 水
- 木
- 金
- 土
abbr_month_names:
-
- 1月
- 2月
- 3月
- 4月
- 5月
- 6月
- 7月
- 8月
- 9月
- 10月
- 11月
- 12月
day_names:
- 日曜日
- 月曜日
- 火曜日
- 水曜日
- 木曜日
- 金曜日
- 土曜日
formats:
default: "%Y/%m/%d"
long: "%Y年%m月%d日(%a)"
short: "%m/%d"
month_names:
-
- 1月
- 2月
- 3月
- 4月
- 5月
- 6月
- 7月
- 8月
- 9月
- 10月
- 11月
- 12月
order:
- :year
- :month
- :day
datetime:
distance_in_words:
about_x_hours:
one: 約1時間
other: 約%{count}時間
about_x_months:
one: 約1ヶ月
other: 約%{count}ヶ月
about_x_years:
one: 約1年
other: 約%{count}年
almost_x_years:
one: 1年弱
other: "%{count}年弱"
half_a_minute: 30秒前後
less_than_x_seconds:
one: 1秒以内
other: "%{count}秒未満"
less_than_x_minutes:
one: 1分以内
other: "%{count}分未満"
over_x_years:
one: 1年以上
other: "%{count}年以上"
x_seconds:
one: 1秒
other: "%{count}秒"
x_minutes:
one: 1分
other: "%{count}分"
x_days:
one: 1日
other: "%{count}日"
x_months:
one: 1ヶ月
other: "%{count}ヶ月"
x_years:
one: 1年
other: "%{count}年"
prompts:
second: 秒
minute: 分
hour: 時
day: 日
month: 月
year: 年
errors:
format: "%{attribute}%{message}"
messages:
accepted: を受諾してください
blank: を入力してください
confirmation: と%{attribute}の入力が一致しません
empty: を入力してください
equal_to: は%{count}にしてください
even: は偶数にしてください
exclusion: は予約されています
greater_than: は%{count}より大きい値にしてください
greater_than_or_equal_to: は%{count}以上の値にしてください
inclusion: は一覧にありません
invalid: は不正な値です
less_than: は%{count}より小さい値にしてください
less_than_or_equal_to: は%{count}以下の値にしてください
model_invalid: 'バリデーションに失敗しました: %{errors}'
not_a_number: は数値で入力してください
not_an_integer: は整数で入力してください
odd: は奇数にしてください
other_than: は%{count}以外の値にしてください
present: は入力しないでください
required: を入力してください
taken: はすでに存在します
too_long: は%{count}文字以内で入力してください
too_short: は%{count}文字以上で入力してください
wrong_length: は%{count}文字で入力してください
template:
body: 次の項目を確認してください
header:
one: "%{model}にエラーが発生しました"
other: "%{model}に%{count}個のエラーが発生しました"
helpers:
select:
prompt: 選択してください
submit:
create: 登録する
submit: 保存する
update: 更新する
number:
currency:
format:
delimiter: ","
format: "%n%u"
precision: 0
separator: "."
significant: false
strip_insignificant_zeros: false
unit: 円
format:
delimiter: ","
precision: 3
separator: "."
significant: false
strip_insignificant_zeros: false
human:
decimal_units:
format: "%n %u"
units:
billion: 十億
million: 百万
quadrillion: 千兆
thousand: 千
trillion: 兆
unit: ''
format:
delimiter: ''
precision: 3
significant: true
strip_insignificant_zeros: true
storage_units:
format: "%n%u"
units:
byte: バイト
eb: EB
gb: GB
kb: KB
mb: MB
pb: PB
tb: TB
percentage:
format:
delimiter: ''
format: "%n%"
precision:
format:
delimiter: ''
support:
array:
last_word_connector: "、"
two_words_connector: "、"
words_connector: "、"
time:
am: 午前
formats:
default: "%Y年%m月%d日(%a) %H時%M分%S秒 %z"
long: "%Y/%m/%d %H:%M"
short: "%m/%d %H:%M"
pm: 午後
ちなみに以下のリンクからコピペしてます。
rails-i18n/ja.yml at master · svenfuchs/rails-i18n · GitHub
最後に同じファイル内に以下を記述する
ja:
activerecord:
attributes:
tasks:
user:
name: 名前
email: メールアドレス
admin: 管理者権限
password: パスワード
password_confirmation: パスワード(確認)
created_at: 登録日時
updated_at: 更新日時
これでユーザー管理機能の基礎ができました。
まとめ
今回は管理機能の箱を作成しました。現状誰でも自由に管理機能をいじることができてしまうので、後々、管理機能への制限を追加していきます。次回からはユーザーがログインするための機能を実装していきます。