Railsのルーティングでいろいろ試した

ルーティングでいろいろ試してみる。

  • resources
  • resource
  • ルーティングのネスト
  • namespaceでグループ化
  • collectionとmember
  • 設定したルーティングがどういったURLになるか確認する



■まずは一般的なresources
Rails.application.routes.draw do
  resources :companies
end


これで生成されるルーティングは以下。

[15] pry(main)> show-routes
      Prefix Verb   URI Pattern                   Controller#Action
   companies GET    /companies(.:format)          companies#index
             POST   /companies(.:format)          companies#create
 new_company GET    /companies/new(.:format)      companies#new
edit_company GET    /companies/:id/edit(.:format) companies#edit
     company GET    /companies/:id(.:format)      companies#show
             PATCH  /companies/:id(.:format)      companies#update
             PUT    /companies/:id(.:format)      companies#update
             DELETE /companies/:id(.:format)      companies#destroy



■resource"s"ではなくresource

複数存在するリソースではなく、単一のリソースである場合は、単数系のresourceを使う。

Rails.application.routes.draw do
  resource :company
end


これで生成されるルーティングは以下。
indexが設定されず、パスにidが付与されない点がresourcesと異なる。

[17] pry(main)> show-routes
      Prefix Verb   URI Pattern             Controller#Action
     company POST   /company(.:format)      companies#create
 new_company GET    /company/new(.:format)  companies#new
edit_company GET    /company/edit(.:format) companies#edit
             GET    /company(.:format)      companies#show
             PATCH  /company(.:format)      companies#update
             PUT    /company(.:format)      companies#update
             DELETE /company(.:format)      companies#destroy



■ルーティングをネストさせる

以下のようにブロックでルーティングを渡すと、ルーティングに階層を作ることができる。

Rails.application.routes.draw do
  resource :company do
    resources :departments
  end
end



[18] pry(main)> show-routes
                 Prefix Verb   URI Pattern                             Controller#Action
    company_departments GET    /company/departments(.:format)          departments#index
                        POST   /company/departments(.:format)          departments#create
 new_company_department GET    /company/departments/new(.:format)      departments#new
edit_company_department GET    /company/departments/:id/edit(.:format) departments#edit
     company_department GET    /company/departments/:id(.:format)      departments#show
                        PATCH  /company/departments/:id(.:format)      departments#update
                        PUT    /company/departments/:id(.:format)      departments#update
                        DELETE /company/departments/:id(.:format)      departments#destroy
                company POST   /company(.:format)                      companies#create
            new_company GET    /company/new(.:format)                  companies#new
           edit_company GET    /company/edit(.:format)                 companies#edit
                        GET    /company(.:format)                      companies#show
                        PATCH  /company(.:format)                      companies#update
                        PUT    /company(.:format)                      companies#update
                        DELETE /company(.:format)                      companies#destroy


さらにdepartmentsの下にemployeesをネストさせるとこうなる。

[19] pry(main)> show-routes
                          Prefix Verb   URI Pattern                                                      Controller#Action
    company_department_employees GET    /company/departments/:department_id/employees(.:format)          employees#index
                                 POST   /company/departments/:department_id/employees(.:format)          employees#create
 new_company_department_employee GET    /company/departments/:department_id/employees/new(.:format)      employees#new
edit_company_department_employee GET    /company/departments/:department_id/employees/:id/edit(.:format) employees#edit
     company_department_employee GET    /company/departments/:department_id/employees/:id(.:format)      employees#show
                                 PATCH  /company/departments/:department_id/employees/:id(.:format)      employees#update
                                 PUT    /company/departments/:department_id/employees/:id(.:format)      employees#update
                                 DELETE /company/departments/:department_id/employees/:id(.:format)      employees#destroy
             company_departments GET    /company/departments(.:format)                                   departments#index
                                 POST   /company/departments(.:format)                                   departments#create
          new_company_department GET    /company/departments/new(.:format)                               departments#new
         edit_company_department GET    /company/departments/:id/edit(.:format)                          departments#edit
              company_department GET    /company/departments/:id(.:format)                               departments#show
                                 PATCH  /company/departments/:id(.:format)                               departments#update
                                 PUT    /company/departments/:id(.:format)                               departments#update
                                 DELETE /company/departments/:id(.:format)                               departments#destroy
                         company POST   /company(.:format)                                               companies#create
                     new_company GET    /company/new(.:format)                                           companies#new
                    edit_company GET    /company/edit(.:format)                                          companies#edit
                                 GET    /company(.:format)                                               companies#show
                                 PATCH  /company(.:format)                                               companies#update
                                 PUT    /company(.:format)                                               companies#update
                                 DELETE /company(.:format)                                               companies#destroy



■namespaceを使ってグループ化する

namespaceを使うことで、ブロックに渡したルーティングをグループ化することができる。
moduleオプションを使うことでも、このnamespaceと同じようなことができるみたい。→Railsのルーティングを極める (後編)

Rails.application.routes.draw do
  namespace :admin do
    resources :users
  end
end



[20] pry(main)> show-routes
         Prefix Verb   URI Pattern                     Controller#Action
    admin_users GET    /admin/users(.:format)          admin/users#index
                POST   /admin/users(.:format)          admin/users#create
 new_admin_user GET    /admin/users/new(.:format)      admin/users#new
edit_admin_user GET    /admin/users/:id/edit(.:format) admin/users#edit
     admin_user GET    /admin/users/:id(.:format)      admin/users#show
                PATCH  /admin/users/:id(.:format)      admin/users#update
                PUT    /admin/users/:id(.:format)      admin/users#update
                DELETE /admin/users/:id(.:format)      admin/users#destroy



■collectionとmember

resoucesで追加されるルーティング(index/create/new/edit/show/update/destroy)以外の
ルーティングを追加したい場合に、collectionかmemberを使う。

Rails.application.routes.draw do
  resources :users do
    collection do
      get :search
    end
    member do
      get :detail
    end
  end
end


collectionにはパスにidが付与されず、memberにはパスにidが付与される。
個別のリソースにアクションを設定するのか、
リソース全体にアクションを設定するかで使い分ければいいみたい。

[21] pry(main)> show-routes
      Prefix Verb   URI Pattern                 Controller#Action
search_users GET    /users/search(.:format)     users#search
 detail_user GET    /users/:id/detail(.:format) users#detail
       users GET    /users(.:format)            users#index
             POST   /users(.:format)            users#create
    new_user GET    /users/new(.:format)        users#new
   edit_user GET    /users/:id/edit(.:format)   users#edit
        user GET    /users/:id(.:format)        users#show
             PATCH  /users/:id(.:format)        users#update
             PUT    /users/:id(.:format)        users#update
             DELETE /users/:id(.:format)        users#destroy



■実際のURLがどうなるか確認する

設定したルーティングがどういったURLになるのかを確認できる。

[22] pry(main)> app.search_users_path
=> "/users/search"
[23] pry(main)> app.search_users_url
=> "http://www.example.com/users/search"
[24] pry(main)> app.user_path(1)
=> "/users/1"
[25] pry(main)> app.user_url(1)
=> "http://www.example.com/users/1"


参考にさせていただきました:
techracho.bpsinc.jp

railsguides.jp

change_columnでmigrateしたらrollbackできなかった

change_columnでmigrateしたあとにrollbackしようとしたらrollbackできなかった…。
そのときのエラーがこれ。

[] be rake db:rollback
== 20160915054652 AddTimestampsToMember: reverting ============================
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:

ActiveRecord::IrreversibleMigration


???だったが、
この「ActiveRecord::IrreversibleMigration」エラーというのが「不可逆なマイグレーション」、
つまり取り消せないマイグレーションですよ!ということらしい。


いろいろ調べてみたら、
「changeでは特定のメソッドでしかrollbackが利かない」、ということがわかりました。
railsguides.jp

add_column
add_index
add_reference
add_timestamps
add_foreign_key
create_table
create_join_table
drop_table (ブロックを渡す必要あり)
drop_join_table (ブロックを渡す必要あり)
remove_timestamps
rename_column
rename_index
remove_reference
rename_table

上記であれば、rollbackするとどうなるかをActiveRecordが判断してrollbackしてくれるけど、
それ以外だと自分で定義しないといかんということみたいです。
(今回change_columnを使ってるためにrollbackできなかったっぽい)

じゃあ、rollbackするときはこうして!っていうのを書くときどうするかというと、
reversibleメソッドを使う、もしくはupメソッド・downメソッドを書けばいいそう。


今回はup・downで、upメソッドにmigrateしたい処理、
downメソッドにrollbackするときの処理を書いて、無事migrate→rollbackできるようになりました。


参考にさせていただきました:
blog.jnito.com

newとbuildに違いはあるのか

結論から言うと機能的な違いはないようで、buildは「newメソッドのエイリアス」とのこと。
new - リファレンス - - Railsドキュメント

コンソールで試してみたらたしかに違いはなさそう。

[3] pry(main)> company = Company.new(id: 1)
=> #<Company:0x007fc4d742ff38 id: 1, name: nil, address: nil, phone_number: nil, mail_address: nil, created_at: nil, updated_at: nil>
[7] pry(main)> company.departments.new
=> #<Department:0x007fc4d70c9948 id: nil, name: nil, company_id: 1, deleted_at: nil, created_at: nil, updated_at: nil>
[8] pry(main)> company.departments.build
=> #<Department:0x007fc4d31e0560 id: nil, name: nil, company_id: 1, deleted_at: nil, created_at: nil, updated_at: nil>


ただ、暗黙的な使い分けはあるようで、
モデルの関係が1:nのとき、1のものにはnewを、nのものにはbuildを使うみたい。
(たしかにドキュメントの例でもそうなってる…)
[Rails][ActiveRecord]modelのnewとbuildの違いについて | Coffee Breakにプログラミング備忘録


例えば、Company(会社)とDepartment(部署)で1:nだとしたら、

Company.new
company.departments.build

となる。