【Rails】コントローラーのリファクタリング

# はじめに
ポートフォリオで、コントローラーのリファクタリングをやったので、備忘録として記事を書きます。

#環境
・Ruby 2.6.3
・Ruby on Rails 5.2.5


# リファクタリング1つ目 concemsを使う
共通記述を複数のコントローラーで使う時にやる
 app/controllers/concernsにファイルを追加し、必要箇所で読み込ませる

```ruby:controllers/concerns/search.rb
module Search
  extend ActiveSupport::Concern

  def search
    @keyword = params[:word]
    redirect_to request.referer, notice: "検索文字を入れて下さい" if @keyword.blank?
    searcher = Searcher.new(params[:word].split(/[[:blank:]]+/))

    @users = Kaminari.paginate_array(searcher.users).page(params[:page]).per(12)
    @groups = Kaminari.paginate_array(searcher.groups).page(params[:page]).per(12)
    @posts = Kaminari.paginate_array(searcher.posts).page(params[:page]).per(12)
  end
end

```

```ruby:controllers/user/searches_controller.rb
class User::SearchesController < ApplicationController
  include Search
  before_action :search
end
```

```ruby:controllers/admin/searches_controller.rb
class Admin::SearchesController < ApplicationController
  include Search
  before_action :search
end
```
これで同じ記述の箇所はスッキリ〜〜

# リファクタリング２つ目 application_controller.rbにかいて継承
複数のコントローラに同じ処理が記述されている場合(継承)に役立つ

```ruby:controllers/user/●●●●●_controller.rb
class ●●●●●Controller < ApplicationController
  before_action :authorize_owner

  private

  def authorize_owner
    redirect_to root_path unless current_user.owner?
  end
end
```
authorize_ownerメソッドが定義されていて、このメソッドを複数のコントローラーで使うよ！って時に
application_controller.rbに記載して継承すれば、記述量少なくなります。
※今回はauthorize_ownerメソッド使ってるけど、例として使っているのでどんなメソッドでもいい


```ruby:controllers/user/application_controller.rb
class ApplicationController < ApplicationController
  private

  def authorize_owner
    redirect_to root_path unless current_user.owner?
  end
end
```
↓継承したいコントローラーに。

```ruby:controllers/user/●●●●●_controller.rb
class ●●●●●Controller < ApplicationController
  before_action :authorize_owner
end
```

# リファクタリング3つ目 callbackを利用して共通化
定義したメソッドをbefore_actionなどで共通化させちゃう方法
複数のアクションに同じ処理が記述されている場合に役立つ

```ruby:controllers/user/●●●●●_controller.rb
class User::PostsController < ApplicationController
  before_action :set_group, only: %i[new index show create update destroy]
  before_action :set_post, only: %i[show update destroy]

  def new
    @post = Post.new
  end

  def index
    @posts = @group.posts.includes(:user).order(updated_at: :desc).page(params[:page]).per(12)
  end

  def show
    @comment = Comment.new

    respond_to do |format|
      format.html do
      end
      format.csv do
        send_data render_to_string, filename: "投稿詳細.csv", type: :csv
      end
    end
  end

 一部アクション割愛 

  private
#ここで記述が重なるコードをメソッド化
  def set_group
    @group = Group.find(params[:group_id])
  end

  def set_post
    @post = Post.find(params[:id])
  end
#ここまで 
#これをbefore_actionで呼び出しちゃえばおｋ

end


```

# リファクタリング4つ目 王道モデルにメソッド定義
長ったらしいコードをモデルに定義してコントローラーをすっきりしようよ作戦

```ruby:controllers/user/homes_controller.rb 
class User::HomesController < ApplicationController
  def top
    @group_ranks = Group.find(GroupUser.group(:group_id).order("count(group_id) desc").limit(6).pluck(:group_id))  
    @admins = Admin.first(6)
  end
end

#この部分をメソッド化してスッキリさせる#
Group.find(GroupUser.group(:group_id).order("count(group_id) desc").limit(6).pluck(:group_id))  

```

モデルに定義

```ruby:models/group.rb
 # ランキング用メソッド
  def self.all_group_ranks
    find(GroupUser.group(:group_id).order("count(group_id) desc").limit(6).pluck(:group_id))
  end
```

コントローラーに呼び出す

```ruby:controllers/user/homes_controller.rb 
class User::HomesController < ApplicationController
  def top
    @group_ranks = Group.all_group_ranks # Group.rbでメソッド定義
    @admins = Admin.first(6)
  end
end
```


###以上自分が実際にやったリファクタリングでした〜〜