概要
ユーザ登録ページへのルーティングを作成します。その前提条件として、2つ目のコントローラを作成します。この先実装していくユーザ登録機能の第一歩です。
Usersコントローラ
Usersコントローラの生成
StaticPagesコントローラに次ぐ2つ目のコントローラとして、Usersコントローラを生成します。まず現時点では、新規ユーザー用のユーザー登録ページ(スタブ)のみを実装した、最も簡単な形でコントローラの生成・実装を行っていきます。
コントローラの作成はrails generate controller
コマンドで行います。コントローラ作成のために与える引数は、以下の通りとします。
- コントローラ名…
Users
- 最初に定義するアクション名…
new
# rails generate controller Users new
Running via Spring preloader in process 1812
create app/controllers/users_controller.rb
route get 'users/new'
invoke erb
create app/views/users
create app/views/users/new.html.erb
invoke test_unit
create test/controllers/users_controller_test.rb
invoke helper
create app/helpers/users_helper.rb
invoke test_unit
invoke assets
invoke coffee
create app/assets/javascripts/users.coffee
invoke scss
create app/assets/stylesheets/users.scss
rails generage controller Users new
により、以下のリソースが生成されました。
- Usersコントローラ
-
users/new
へのGET
リクエストに対するルーティング情報 -
users
ビュー - Usersコントローラに対するテスト
-
users_helper
ヘルパー -
users
に対するCoffeeScript形式のスクリプト -
users
に対するSCSS形式のスタイルシート
現時点におけるUsersコントローラとその周辺リソース
生成されたばかりのUsersコントローラのソースコードは、以下のようになっています。
class UsersController < ApplicationController
def new
end
end
app/controllers/users_controller.rb
のコードから、以下のことがわかります。
-
UsersController
クラスが定義されている- UsersController
クラスは、
ApplicationController`クラスを継承している
- UsersController
-
UsersController
クラスでは、new
メソッドが定義されている
続いて、生成されたばかりのapp/views/users/new.html.erb
のソースコードは以下の通りです。
<h1>Users#new</h1>
<p>Find me in app/views/users/new.html.erb</p>
さらに、生成されたばかりのtest/controllers/users_controller_test.rb
のソースコードは以下の通りです。
require 'test_helper'
class UsersControllerTest < ActionDispatch::IntegrationTest
test "should get new" do
get users_new_url
assert_response :success
end
end
この時点で、テストは問題なく通ります。
# rails test
...略
8/8: [=============================================================================================================================================================] 100% Time: 00:00:06, Time: 00:00:06
Finished in 6.55124s
8 tests, 18 assertions, 0 failures, 0 errors, 0 skips
演習 - Usersコントローラ
1. 表 5.1を参考にしながらリスト 5.41を変更し、users_new_url
ではなくsignup_path
を使えるようにしてみてください。
require 'test_helper'
class UsersControllerTest < ActionDispatch::IntegrationTest
test "should get new" do
- get users_new_url
+ get signup_path
assert_response :success
end
end
2. 先ほどの変更を加えたことにより、テストがred
になったことを確認してください。なお、この演習はテスト駆動開発 (コラム 3.3) で説明したred
/green
のリズムを作ることを目的としています。このテストは次の5.4.2でgreen
になるよう修正します。
# rails test
...略
ERROR["test_should_get_new", UsersControllerTest, 1.619302900013281]
test_should_get_new#UsersControllerTest (1.62s)
NameError: NameError: undefined local variable or method `signup_path' for #<UsersControllerTest:0x0000558df747d378>
test/controllers/users_controller_test.rb:5:in `block in <class:UsersControllerTest>'
8/8: [=============================================================================================================================================================] 100% Time: 00:00:01, Time: 00:00:01
Finished in 1.71337s
8 tests, 17 assertions, 0 failures, 1 errors, 0 skips
無事(?)テスト結果で不適合が指摘されました。「signup_path
というメソッドが定義されていない」という不適合ですね。Railsにおけるエンドポイントの扱いにおいて、_path
や_url
で終わるメソッドは、名前付きルートを定義したときに自動で定義されるのでしたね。必要になるのは、/signupというエンドポイントです。
ユーザー登録用URL
ユーザー登録ページのエンドポイントの変更
表 5.1でも言及されていたように、新規ユーザー登録ページのURLは、/users/newではなくて/signupにしたいです。ルーティングの変更が必要になります。
ルーティングの変更なので、ここで変更するファイルは、config/routes.rb
です。では早速、先ほどの演習でも登場した/signupというエンドポイントを早速定義してみましょう。
Rails.application.routes.draw do
- get 'users/new'
root 'static_pages#home'
get '/help', to: 'static_pages#help'
get '/about', to: 'static_pages#about'
get '/contact', to: 'static_pages#contact'
+ get '/signup', to: 'users#new'
end
改めてrails test
を実行してみます。
# rails test
...略
8/8: [=============================================================================================================================================================] 100% Time: 00:00:01, Time: 00:00:01
Finished in 1.55368s
8 tests, 18 assertions, 0 failures, 0 errors, 0 skips
先ほどの演習の内容と合わせて、これでテストが通るようになったのが確認できます。
Homeページのボタンに、ユーザー登録ページへのリンクを追加
先ほど行ったルーティングの変更で、/signupに対し、signup_path
やsignup_url
というメソッドを呼び出せるようになりました。早速Homeページに/signupへのリンクを追加しましょう。リダイレクトではないので、signup_path
のほうを使います。
<div class="center jumbotron">
<h1>Welcome to the Sample App</h1>
<h2>
This is the home page for the
<a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
sample application.
</h2>
- <%= link_to "Sign up now!", '#', class: "btn btn-lg btn-primary" %>
+ <%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %>
</div>
<%= link_to image_tag("rails.png", alt: "Rails logo"),
'http://rubyonrails.org/' %>
最後に、signupページ用のビューのスタブの先頭に、app/views/layouts/application.html.erb
を参照するための設定を追加します。ページタイトルは'Sign up'とします。
+ <% provide(:title, 'Sign up') %>
<h1>Users#new</h1>
<p>Find me in app/views/users/new.html.erb</p>
この部分は、app/views/layouts/application.html.erb
の以下の部分に展開されるのでしたね。
```erb:app/views/layouts/application.html.erb(抜粋)
<%= yield %>
現時点で、/signupをブラウザで表示した結果は以下のようになります。
<img width="1164" alt="スクリーンショット 2019-09-28 10.26.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/4d0b4a59-6935-5ee8-b8e8-9c9b1479cd08.png">
# 演習 - ユーザー登録用URL
## 1.1. もしまだ[5.4.1.1](https://railstutorial.jp/chapters/filling_in_the_layout?version=5.1#sec-exercises_users_controller)の演習に取り掛かっていなければ、まずは[リスト 5.41](https://railstutorial.jp/chapters/filling_in_the_layout?version=5.1#code-user_new_test)のように変更し、名前付きルートsignup_pathを使えるようにしてください。
この部分は、先ほどの演習で変更した部分となります。
## 1.2. また、[リスト 5.43](https://railstutorial.jp/chapters/filling_in_the_layout?version=5.1#code-signup_route)で名前付きルートが使えるようになったので、現時点でテストが`green`になっていることを確認してください。
rails test
...略
8/8: [=============================================================================================================================================================] 100% Time: 00:00:01, Time: 00:00:01
Finished in 1.70987s
8 tests, 18 assertions, 0 failures, 0 errors, 0 skips
きちんとテストは通りますね。
## 2.1. 先ほどのテストが正しく動いていることを確認するため、signupルートの部分をコメントアウトし、テスト redになることを確認してください。
`config/routes.rb`を、以下のように変更します。
```diff:config/routes.rb
Rails.application.routes.draw do
get 'users/new'
root 'static_pages#home'
get '/help', to: 'static_pages#help'
get '/about', to: 'static_pages#about'
get '/contact', to: 'static_pages#contact'
- get '/signup', to: 'users#new'
+ # get '/signup', to: 'users#new'
end
# rails test
...略
ERROR["test_should_get_home", StaticPagesControllerTest, 0.4042917999904603]
test_should_get_home#StaticPagesControllerTest (0.41s)
ActionView::Template::Error: ActionView::Template::Error: undefined local variable or method `signup_path' ...略
ERROR["test_should_get_root", StaticPagesControllerTest, 0.5494068999832962]
test_should_get_root#StaticPagesControllerTest (0.55s)
ActionView::Template::Error: ActionView::Template::Error: undefined local variable or method `signup_path' ...略
ERROR["test_layout_links", SiteLayoutTest, 2.0050760000012815]
test_layout_links#SiteLayoutTest (2.01s)
ActionView::Template::Error: ActionView::Template::Error: undefined local variable or method `signup_path' ...略
ERROR["test_should_get_new", UsersControllerTest, 2.0233185999968555]
test_should_get_new#UsersControllerTest (2.02s)
NameError: NameError: undefined local variable or method `signup_path' ...略
8/8: [=============================================================================================================================================================] 100% Time: 00:00:02, Time: 00:00:02
Finished in 2.07825s
8 tests, 8 assertions, 0 failures, 4 errors, 0 skips
テストが通らなくなりました。signup_path
というメソッドが定義されていない、というエラーですね。/signupに対する名前付きルートが書かれていないとこうなります。
実際、現時点でsignup_path
メソッドは定義されていません。以下はrails console
での確認結果です。
>> app.signup_path
...略
NoMethodError (undefined method `signup_path' ...略)
2.2. 確認できたら、コメントアウトを解除してgreen
の状態に戻してください。
Rails.application.routes.draw do
get 'users/new'
root 'static_pages#home'
get '/help', to: 'static_pages#help'
get '/about', to: 'static_pages#about'
get '/contact', to: 'static_pages#contact'
- # get '/signup', to: 'users#new'
+ get '/signup', to: 'users#new'
end
# rails test
...略
8/8: [=============================================================================================================================================================] 100% Time: 00:00:02, Time: 00:00:02
Finished in 2.18233s
8 tests, 18 assertions, 0 failures, 0 errors, 0 skips
今度はきちんとテストが通りますね。
>> app.signup_path
=> "/signup"
rails console
でも、signup_path
メソッドが存在することが確認できました。
3.1. リスト 5.32の統合テストにsignupページにアクセスするコードを追加してください (getメソッドを使います)。
require 'test_helper'
class SiteLayoutTest < ActionDispatch::IntegrationTest
test "layout links" do
get root_path
assert_template 'static_pages/home'
assert_select "a[href=?]", root_path, count: 2
assert_select "a[href=?]", help_path
assert_select "a[href=?]", about_path
assert_select "a[href=?]", contact_path
get contact_path
assert_select "title", full_title("Contact")
+ get signup_path
+ assert_select "title", full_title("Sign up")
end
end
end
3.2.コードを追加したら実際にテストを実行し、結果が正しいことを確認してください。
# rails test:integration
...略
1/1: [=============================================================================================================================================================] 100% Time: 00:00:01, Time: 00:00:01
Finished in 1.62317s
1 tests, 7 assertions, 0 failures, 0 errors, 0 skips
テストは問題なく通りました。
3.余談 signupページのSign up
ではなくSigh up
にしたらテスト結果がred
になることを確認します。
+ <% provide(:title, 'Sign up') %>
- <% provide(:title, 'Sigh up') %>
<h1>Users#new</h1>
<p>Find me in app/views/users/new.html.erb</p>
このときのテスト結果は以下の通りになります。
# rails test:integration
...略
FAIL["test_layout_links", SiteLayoutTest, 1.7456585000036284]
test_layout_links#SiteLayoutTest (1.75s)
<Sign up | Ruby on Rails Tutorial Sample App> expected but was
<Sigh up | Ruby on Rails Tutorial Sample App>..
Expected 0 to be >= 1.
test/integration/site_layout_test.rb:15:in `block in <class:SiteLayoutTest>'
1/1: [=============================================================================================================================================================] 100% Time: 00:00:01, Time: 00:00:01
Finished in 1.75320s
1 tests, 7 assertions, 1 failures, 0 errors, 0 skips
無事(?)不適合が指摘されました。
もちろん、app/views/users/new.html.erb
の内容を元に戻しておくのも忘れずに。
- <% provide(:title, 'Sigh up') %>
+ <% provide(:title, 'Sign up') %>
<h1>Users#new</h1>
<p>Find me in app/views/users/new.html.erb</p>
この先の方針
これにて、Railsチュートリアル第5章は一通り完走となりました。今後は、以下の機能を追加していくこととなります。
- ユーザー登録
- サインイン
- サインアウト
- マイクロポスト機能
- 他のユーザーのフォロー機能