Railsのcontroller,routesの書き方とについて考えてみた。

#初めに

こんな記事を読みました。

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
```

とします。

またモデルファイルに

```ruby:user.rb
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ですが

```ruby 
resources :users do 
  resources :actives, only: [:index, :create]
  resources :stops,   only: [:index, :create]
end 
```

このようにするとcontrollers/以下のstops_controller.rbを探しに行ってしまします。

controllers/users/以下のファイルを探しに行ってくれるようにするために

```ruby 
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の中身はこんな感じ

```ruby:actives_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

```

```ruby:stops_controller.rb
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に

```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に

```ruby 
    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に

```ruby 
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しか書かないのであればネストさせるのは必須なのかなと思いました。

おわり:sunny: