特異クラスの使い方

前の記事の最後に出したコードで特異クラスを使ってます。

def build_book
  books = Book.joins('LEFT JOIN reviews ON books.id = reviews.book_id').
      select('books.id bid, reviews.id rid, reviews.book_id, reviews.body')
  res = {}
  books.each { |rec|
    book = res[rec.bid]
     
    if book == nil
      book = Book.new
      class << book
        attr_accessor :reviews
      end
      res[rec.bid] = book
      book.id = rec.bid
      book.reviews = Array.new
    end
  〜略〜
  }
  
  res.values
end

通常のO-Rマッピングの操作(findなど)でActive Recordが返してくるモデルには、関連先テーブルのデータもフィールドとして含めて返してくれます。

例えば、Bookモデルだったら、BOOKSテーブルと関連するREVIEWSテーブルのデータは、Book.reviews としてモデルを返してくれます。

しかし、今回はBookモデルを自分でnewして、Book.reviewsを持つモデルをつくろうとしてます。
ところが、Bookモデルのクラス定義は以下。

class Book < ActiveRecord::Base
  has_many :reviews
end

自分で普通にnewしたBookモデルでは、reviewsフィールドに値をセットできません。

だからといて、わざわざそのためにクラス定義するのも面倒だし。

そこで特異クラスを使ってみました。 attr_Accessor :reviews を追加定義することで、モデルを再現しています。

本当にこういう使い方でいいのかな?