ユーザー登録ページのカスタマイズ
本章ではユーザー登録ページ /users/sign_up
で使われる view ファイルを編集し、デザインを調整します。
変更前 view ファイルの確認
devise のコマンドで作成した直後ですと、ユーザー登録用の view ファイルは以下のようになっています。
(変更前): app/views/devise/registrations/new.html.erb
<h2>Sign up</h2>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
</div>
<div class="field">
<%= f.label :password %>
<% if @minimum_password_length %>
<em>(<%= @minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "new-password" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "new-password" %>
</div>
<div class="actions">
<%= f.submit "Sign up" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
view の修正
では、ユーザー登録の view を次のように変更してください。
(変更後): app/views/devise/registrations/new.html.erb
<%= form_with scope: resource, as: resource_name, url: registration_path(resource_name), class: "space-y-6 w-3/4 max-w-lg" ,local: true do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>
<label class="block text-xl font-bold text-gray-700">ユーザー登録</label>
<div class="mt-1">
<label class="text-gray-700 text-md">
メールアドレス
</label>
<%= f.email_field :email, autofocus: true, autocomplete: "email", class: "shadow-sm focus:ring-indigo-500 focus:border-indigo-500 mt-1 block w-full sm:text-sm placeholder-gray-400 border border-gray-300 rounded-md", placeholder: "test@exeample.com" %>
</div>
<div class="mt-1">
<label class="text-gray-700 text-md">
ニックネーム
</label>
<%= f.text_field :nickname, autocomplete: "nickname", class: "shadow-sm focus:ring-indigo-500 focus:border-indigo-500 mt-1 block w-full sm:text-sm placeholder-gray-400 border border-gray-300 rounded-md", placeholder: "エンジニアの卵" %>
</div>
<div class="mt-1">
<label class="text-gray-700 text-md">
パスワード (6文字以上)
</label>
<%= f.password_field :password, autocomplete: "new-password", class: "shadow-sm focus:ring-indigo-500 focus:border-indigo-500 mt-1 block w-full sm:text-sm placeholder-gray-400 border border-gray-300 rounded-md", placeholder: "pass1234" %>
</div>
<div class="mt-1">
<label class="text-gray-700 text-md">
確認用パスワード
</label>
<%= f.password_field :password_confirmation, autocomplete: "new-password", class: "shadow-sm focus:ring-indigo-500 focus:border-indigo-500 mt-1 block w-full sm:text-sm placeholder-gray-400 border border-gray-300 rounded-md", placeholder: "pass1234" %>
</div>
<button type="submit" class="group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
<%= f.submit "ユーザー登録" %>
</button>
<% end %>
画面確認
では開発用サーバを起動し、ブラウザで確認していきましょう。
bin/dev
コマンドで開発用サーバを起動します。
$ bin/dev
09:33:09 web.1 | started with pid 7086
09:33:09 css.1 | started with pid 7087
09:33:11 web.1 | => Booting Puma
09:33:11 web.1 | => Rails 7.0.3 application starting in development
09:33:11 web.1 | => Run `bin/rails server --help` for more startup options
09:33:11 web.1 | Puma starting in single mode...
09:33:11 web.1 | * Puma version: 5.6.4 (ruby 3.0.4-p208) ("Birdie's Version")
09:33:11 web.1 | * Min threads: 5
09:33:11 web.1 | * Max threads: 5
09:33:11 web.1 | * Environment: development
09:33:11 web.1 | * PID: 7086
09:33:11 web.1 | * Listening on http://127.0.0.1:3000
09:33:11 web.1 | * Listening on http://[::1]:3000
09:33:11 web.1 | Use Ctrl-C to stop
09:33:12 css.1 |
09:33:12 css.1 | Rebuilding...
09:33:12 css.1 | Done in 201ms.
サーバを起動できたら、ブラウザで http://localhost:3000/users/sign_up
にアクセスします。
<img width="657" alt="image" src="https://user-images.githubusercontent.com/68495563/180105295-4980a292-4cda-4b05-8921-67860adf6af6.png">
このような画面になっていれば OK です。
画面全体のレイアウト調整
ユーザー登録画面を見ると分かると思いますが、全体的にコンテンツがブラウザ内の左側に寄ってしまっていますね。
<img width="1429" alt="image" src="https://user-images.githubusercontent.com/68495563/180105517-cca2e100-83b7-414d-ac78-914d4dcf03a2.png">
TechLog は 1 カラム構成のアプリケーションであるため、コンテンツが真ん中になるように調整しましょう。
修正するのは、各 view を読み込んでいる大元の view である app/views/layouts/application.html.erb
ファイルです。
(変更前): app/views/layouts/application.html.erb
...
<body>
<main class="container mx-auto mt-28 px-5 flex">
<%= yield %>
</main>
</body>
...
TailwindCSS を指定して rails new
コマンドを実行したため、TailwindCSS 仕様のスタイルクラスが最初から適用されていることが分かります。
今回は真ん中に寄せるスタイルを適用したいので、上記の部分を以下のように変更してください。
(ついでに背景色も変更)
(変更後): app/views/layouts/application.html.erb
...
<body class="h-screen bg-blue-50">
<main class="container mx-auto mt-20 py-8 px-5 flex items-center justify-center">
<%= yield %>
</main>
</body>
...
変更したら再度ブラウザで http://localhost:3000/users/sign_up
にアクセスします。
コンテンツが真ん中に寄ったことが確認できます。
<img width="1199" alt="image" src="https://user-images.githubusercontent.com/68495563/180105922-7d005ec2-1075-4f94-a9d4-be41052d46d7.png">
テスト作成
デザイン調整を行なうにあたり、devise がデフォルトで用意している view ファイルから当然ながら変わっています。
言い換えると、devise の gem 自体でテストされている view とは異なる view を使っております。
そのため、修正した後の画面で想定通りの動作をすることを確認するテストを追加しましょう。
System Spec ファイル作成
トップページ (Home#top) の時と同様、System Spec ファイルをコマンドで生成します。
$ bundle exec rails g rspec:system user
create spec/system/users_spec.rb
テスト修正
次は作成されたテストファイル spec/system/users_spec.rb
を修正していきましょう。
spec/system/users_spec.rb
require 'rails_helper'
describe 'User', type: :system do
before { driven_by :selenium_chrome_headless }
# ユーザー情報入力用の変数
let(:email) { 'test@example.com' }
let(:nickname) { 'テスト太郎' }
let(:password) { 'password' }
let(:password_confirmation) { password }
describe 'ユーザー登録機能の検証' do
before { visit '/users/sign_up' }
# ユーザー登録を行う一連の操作を subject にまとめる
subject do
fill_in 'user_nickname', with: nickname
fill_in 'user_email', with: email
fill_in 'user_password', with: password
fill_in 'user_password_confirmation', with: password_confirmation
click_button 'ユーザー登録'
end
context '正常系' do
it 'ユーザーを作成できる' do
expect { subject }.to change(User, :count).by(1) # Userが1つ増える
expect(current_path).to eq('/') # ユーザー登録後はトップページにリダイレクト
end
end
end
end
ここまでで一旦、テストを実行しておきましょう。
$ bin/rspec spec/system/users_spec.rb
...
User
ユーザー登録機能の検証
正常系
DEBUGGER[rspec#59177]: Attaching after process 59169 fork to child process 59177
ユーザーを作成できる
Finished in 2.66 seconds (files took 0.71727 seconds to load)
1 example, 0 failures
テストに通ることを確認してください。
正常系で問題なかったので、続けて異常系 (メールアドレスが空欄の場合など) に関するテストも追加した全文がこちらです。
require 'rails_helper'
describe 'User', type: :system do
before { driven_by :selenium_chrome_headless }
# ユーザー情報入力用の変数
let(:email) { 'test@example.com' }
let(:nickname) { 'テスト太郎' }
let(:password) { 'password' }
let(:password_confirmation) { password }
describe 'ユーザー登録機能の検証' do
before { visit '/users/sign_up' }
# ユーザー登録を行う一連の操作を subject にまとめる
subject do
fill_in 'user_nickname', with: nickname
fill_in 'user_email', with: email
fill_in 'user_password', with: password
fill_in 'user_password_confirmation', with: password_confirmation
click_button 'ユーザー登録'
end
context '正常系' do
it 'ユーザーを作成できる' do
expect { subject }.to change(User, :count).by(1) # Userが1つ増える
expect(current_path).to eq('/') # ユーザー登録後はトップページにリダイレクト
end
end
context '異常系' do
context 'nicknameが空の場合' do
let(:nickname) { '' }
it 'ユーザーを作成せず、エラーメッセージを表示する' do
expect { subject }.not_to change(User, :count) # Userが増えない
expect(page).to have_content("Nickname can't be blank") # エラーメッセージのチェック
end
end
context 'nicknameが20文字を超える場合' do
let(:nickname) { 'あ' * 21 }
it 'ユーザーを作成せず、エラーメッセージを表示する' do
expect { subject }.not_to change(User, :count)
expect(page).to have_content('Nickname is too long (maximum is 20 character')
end
end
context 'emailが空の場合' do
let(:email) { '' }
it 'ユーザーを作成せず、エラーメッセージを表示する' do
expect { subject }.not_to change(User, :count)
expect(page).to have_content("Email can't be blank")
end
end
context 'passwordが空の場合' do
let(:password) { '' }
it 'ユーザーを作成せず、エラーメッセージを表示する' do
expect { subject }.not_to change(User, :count)
expect(page).to have_content("Password can't be blank")
end
end
context 'passwordが6文字未満の場合' do
let(:password) { 'a' * 5 }
it 'ユーザーを作成せず、エラーメッセージを表示する' do
expect { subject }.not_to change(User, :count)
expect(page).to have_content('Password is too short (minimum is 6 characters')
end
end
context 'passwordが128文字を超える場合' do
let(:password) { 'a' * 129 }
it 'ユーザーを作成せず、エラーメッセージを表示する' do
expect { subject }.not_to change(User, :count)
expect(page).to have_content('Password is too long (maximum is 128 characters)')
end
end
context 'passwordとpassword_confirmationが一致しない場合' do
let(:password_confirmation) { "#{password}hoge" } # passwordに"hoge"を足した文字列にする
it 'ユーザーを作成せず、エラーメッセージを表示する' do
expect { subject }.not_to change(User, :count)
expect(page).to have_content("Password confirmation doesn't match Password")
end
end
end
end
end
なお、バリデーションによるエラーメッセージは現在は英語ですが、TechLog は日本語用のアプリですので後に日本語に修正していきます。
その際、このテストも修正することになるので覚えておきましょう。
テスト実行
すべてのテストを実行し、すべて成功することを確認します。
$ bin/rspec
Finished in 5.06 seconds (files took 0.33117 seconds to load)
14 examples, 0 failures
変更をコミット
ここまでの変更をコミットして完了です。
$ git add .
$ git commit -m "ユーザー登録画面の修正"
$ git push