has_many :throughなリレーションで中間テーブルをみつついい感じに絞り込みたい

これまで新しめのアプリではMongoを使ってたんですが、近頃になってようやくActiveRecordをproductionでもりもり使っています。Arelいいですね。

で、本題。こういう場合に、attendances.statusを見てeventsを絞り込みたい。これをかっこよく書くにはどうすればいいか。

class Person < ActiveRecord::Base
  has_many :attendances
  has_many :events, through: :attendances
end

class Attendance < ActiveRecord::Base
  belongs_to :people
  belongs_to :events

  # t.string :status
  STATUSES = %w[registered paid canceled attended absented].freeze
  validates_inclusion_of :status, in: STATUSES
end

class Event < ActiveRecord::Base
end

で、いまの解。もうちょっとかっこいいのはないかしら。

class Person < ActiveRecord::Base
  has_many :attendances
  has_many :events, through: :attendances do
    Attendance::STATUSES.each do |stat|
      class_eval %(def #{stat}; stats(#{stat.dump}); end)
    end
    def stats(*stats)
      where("#{Attendance.quoted_table_name}.status IN ?", stats) 
    end
  end
end

# => person.events.canceled
# => person.events.paid

Event側からstatusごとに数えるときは、実用性に寄せればビューをつくってクロス集計かなぁ。
幸いにしてそうしたくらいで問題になるようなパフォーマンス要件ではないし。