Dragon Arrow written by Tatsuya Nakaji, all rights reserved animated-dragon-image-0164

モデル内のクラスメソッドで効率化(例: 記事が多い順にタグを取得) Rails5.2

Jul 30, 2019

モデル内のクラスメソッドで効率化 Rails5.2



例えば、tagテーブルとarticlesテーブルが存在し、以下のような構造であったとする

(schema.rb)

ActiveRecord::Schema.define(version: xxxx_xx_xx) do
...
  create_table "tags", force: :cascade do |t|
    t.string "name", null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end
  create_table "articles", force: :cascade do |t|
    t.string "title"
    t.text "body"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end
...
end

(models/tag.rb)

class Tag < ApplicationRecord
  has_and_belongs_to_many :articles
end


(models/article.rb)

class Article < ApplicationRecord
  has_and_belongs_to_many :tags
end


viewのなかで、記事が多い順にタグを取得して表示したい。

そういうときは、こういう長い文になります。


<% Tag.select('tags.*', 'count(articles.id) AS acs').left_joins(:articles).group('tags.id').order('acs desc') do |tag| %>
  <li><a href=<%= manage_tag_path(id: tag.id) %>><%= tag.name %></a></li>
<% end %>


もちろん、コントローラの中で

@tags=Tag.select('tags.*', 'count(articles.id) AS acs').left_joins(:articles).group('tags.id').order('acs desc')

としてから@tagsで渡してもいいですが、それだと他のコントローラで使うときに、また宣言をしないといけなくなります


そこで、クラスメソッドを使う

models/tag.rbにクラスメソッドを追加

(models/tag.rb)

class Tag < ApplicationRecord
  has_and_belongs_to_many :articles

# articleが多い順に全てのtagを取得している
  def self.popular_sort_tags
     Tag.select('tags.*', 'count(articles.id) AS acs').left_joins(:articles).group('tags.id').order('acs desc')
  end
end


これで、いつでも

<% Tag.popular_sort_tags.each do |tag| %>
  <li><a href=<%= manage_tag_path(id: tag.id) %>><%= tag.name %></a></li>
<% end %>


てやったり、

コントローラで

@tags=Tag.popular_sort_tags

として

<% @tags.each do |tag| %>
  <li><a href=<%= manage_tag_path(id: tag.id) %>><%= tag.name %></a></li>
<% end %>


で、スマートにまとめることができる。


何回も使うものは定義は1回で済ませる努力をしよう!!