元経理マンが27歳でエンジニアに転向してからのメモ集

元経理マンがエンジニアに転向して現在

Railsでconcernsを使えば、application_controller.rbを汚さずに共通化できる

通常?今までRailsでapplication_controller.rbに共通化した処理を書いていたが、
エラー処理を書いてあるのでできればそちらを使わずに共通化をしたい。ということで、concernsを使ってリファクタリングする。 そもそもconcernsで共通化するのでスタンダード?かも。

お題としては、
- トップページには最新の記事を5件だけ表示したい。(about等複数ページ)
- 記事一覧ページでは最新の記事を20件表示したい。
- 記事は@latest_entriesというインスタンス変数でViewに渡したい。

こちらをリファクタリングしていく様子を記述する。

通常の無駄な記述 (リファクタリング前)

home_controller.rb

class HomeController < ApplicationController
  def index
    @latest_articles = Article.limit(5).order("created_at DESC")
  end
end

articles_controller.rb

class ArticleController < ApplicationController
  def index
    @latest_articles = Article.limit(20).order("created_at DESC")
  end
end

DRYの哲学があるので、共通化をする。

application_controller.rbでリファクタリング(今まで)

application_controller.rb

class ApplicationController < ApplicationController

  def error_hogehoge
  end

  def error_fugafuga
  end

  def latest_articles(num)
    @latest_articles = Article.limit(num).order("created_at DESC")
  end
end

error_hogehogeはエラー処理のメソッドとして、サンプルとして記述してある。

home_controller.rb

class HomeController < ApplicationController
  before_action -> { latest_articles(5) }, only: [:index]

  def index
  end
end

articles_controller.rb

class ArticleController < ApplicationController
  before_action -> { latest_articles(20) }, only: [:index]

  def index
  end
end

こんな感じで共通化していく。 が、application_controller.rbはエラー処理の記述があって、できれば汚したくない! という場合にconcernsを使って共通化もできる。

concernsでリファクタリング

latest_articles.rb

module LatestArticles
  extend ActiveSupport::Concern

  def latest_articles(num)
    @latest_articles = Article.limit(num).order("created_at DESC")
  end

end

application_controller.rb

class ApplicationController < ApplicationController

  def error_hogehoge
  end

  def error_fugafuga
  end

end

ここには何も書かなくても、大丈夫。

home_controller.rb

class HomeController < ApplicationController
  include LatestArticles
  before_action -> { latest_articles(5) }, only: [:index]

  def index
  end
end

articles_controller.rb

class ArticleController < ApplicationController
  include LatestArticles
  before_action -> { latest_articles(20) }, only: [:index]

  def index
  end
end

concernsの方にクラスとかメソッドを記述して、 controllerの方で、include クラス名を記述してあげれば利用できる。

これだけだとあまり有り難みがないかもしれないが、
application_controller.rbに記述しなくても、
concernsで共通化ができる。

使いようによってはもっと複雑なこともできる。はず。