初めに
こんな記事を読みました。
DHHはどのようにRailsのコントローラを書くのか
https://postd.cc/how-dhh-organizes-his-rails-controllers/
この記事の引用なのですがまとめると
「コントローラはデフォルトのCRUDアクションindex、show、new、edit、create、update、destroyのみを使うべき」
とDHHという人は考えているとのこと。
これについて記事の筆者は意見を言っていて気になる人は見に行ってほしいのですが
とりあえずcontrollerを細かく分けで基本的にcrudを書くようなやり方を実践してみました。
またコントローラーが増えることによって逆にわかりづらくなるのを防ぐために
userに関係するものは
users/***_controller.rb
みたいに保存しました。
実装
まず
rails new app
rails g model user name
rails g controller users
とします。
これでroutes.rbに
resources :users
とかけばusersにかんして
crudの設定が終わります。
userにstatusを付ける
次にuserにstatusカラムを追加してそこにactive,stopという属性をenumを使って実装します
rails g migration add_status_to_users
としてマイグレーションファイルに
add_column :users, :status, :integer, default: 0
とします。
またモデルファイルに
enum status: { active: 0, stop: 1}
これを追加
これでuserを作成するとstatusがactiveのuserが作成できます。
ここでactive userとstop userの表示をusers_controllerで実装するのではなくほかにコントローラーを作って実装します。
この時に
rails g controller actives
とするのではなく
rails g controller users::actives
としました。
これでcontrollers/users以下にactives_controller.rbが作成されます。
同じように
rails g controller users:stops
としました。
次にroutes.rbですが
resources :users do
resources :actives, only: [:index, :create]
resources :stops, only: [:index, :create]
end
このようにするとcontrollers/以下のstops_controller.rbを探しに行ってしまします。
controllers/users/以下のファイルを探しに行ってくれるようにするために
resources :users do
scope module: :users do
resources :actives, only: [:index, :create]
resources :stops, only: [:index, :create]
end
end
とすることでちゃんとcontrollers/users以下のファイルへのroutesを作成できました。
actives_controller.rb,stops_controller.rbの中身はこんな感じ
class Users::ActivesController < ApplicationController
def index
@users = User.active
end
def create
user = User.find params[:user_id]
user.active!
redirect_to users_path
end
end
class Users::StopsController < ApplicationController
def index
@users = User.stop
end
def create
user = User.find params[:user_id]
user.stop!
redirect_to users_path
end
end
実際に呼び出す際にネストさせたroutesのurlヘルパーの書き方は
users/index.html.erbに
<% @users.each do |user| %>
<p><%= user.name %></p>
<p><%= user.status %></p>
<%= link_to "stop_user", user_stops_path(user), method: :post %>
<%= link_to "active_user", user_actives_path(user), method: :post %>
<% end %>
みたいにすればOKです。
上の場合はstops#create,actives#createへのroutesですがネストさせた場合
params[:id]
ではなく
params[:user_id]
のように取得するようになります。
follow機能
followみたいな機能に関してもuserに関係するものなのでusers以下にcontroller.rbが作成されたほうが良いのかと思いました。
なので
rails g model follow user_id:integer follow_id:integer
同じデータが複数保存されないように
models/follow.rbに
validate :already_follow
def already_follow
if Follow.exists?(user_id: user_id, follow_id: follow_id)
errors.add(:user_id, "すでにフォローしています")
end
end
としました。
そして
rails g controller users::follows
follows_controller.rbに
class Users::FollowsController < ApplicationController
def index
@follow_users = Follow.where(follow_id: session[:user_id])
end
def create
if session[:user_id]
follow = Follow.new(follow_id: session[:user_id], user_id: params[:user_id])
follow.save
redirect_to users_path
else
redirect_to users_path
end
end
end
とすればフォロー機能が作成できました。
結果
これでuserのstatusを変更したりuserをfollowしたりする機能をcontrollerごとに分けて作ってみました。
結果として
controllers/users以下のコントローラーはuserに関係するものだとすぐにわかるし
一つ一つのコントローラーの中身がかなりシンプルのなりました。
逆に普通に
rails g controller follows
rails g controller actives
rails g controller stops
みたいにしてコントローラーを細かく作っていくと逆に何が何だか分からなくなるかもしれないので
コントローラーにcrudしか書かないのであればネストさせるのは必須なのかなと思いました。
おわり