一部のモデルが一部の操作を実装せず、空のコレクションを返す必要があるように、一連の操作 (そのほとんどは本質的に .where(...) です) をカプセル化し、それをさまざまなモデルに適用するにはどうすればよいですか。(重要でないコードはスキップされます)
私が設計したもの(しかし満足していない):
class ActivityFinder
def self.find(query, limit = nil)
activities = get_activities(query)
activities = activities.sort_by(&:created_at).reverse // some-kind of merge-sort
activities = activities.slice(0, limit) if limit.present?
activities
end
private
def self.get_activities(query)
activities = []
activities += query.apply(ModelA)
activities += query.apply(ModelB)
activities += query.apply(ModelC)
activities
end
end
class ActivityQuery
def created_before(time)
@created_before = time
self
end
def created_after(time)
@created_after = time
self
end
def apply(activity)
activity = activity.where("#{activity.table_name}.created_at < ?", @created_before) if @created_before.present?
activity = activity.where("#{activity.table_name}.created_at >= ?", @created_after) if @created_after.present?
// more operations, not all of them are suported by ModelC
rescue NoMethodError
return []
end
end
使用法
query = ActivityQuery.new.created_before(last_time).with_hash(...)
activities = ActivityFinder.find(query)
嫌いなもの:
- NoMethodError のレスキュー
- モデルごとにフィールドの名前が異なる場合は
case
、クエリ内のステートメントとして処理する必要があり、この方法でクエリ オブジェクトを各モデルに結合します。
だから私はより良い実装のための提案を探しています
アップデート
問題は、ActiveModel から取得した任意のオブジェクト (ActiveRecord::Relation など) を渡したいため、メソッドを使用してモジュールを定義し (必要に応じてオーバーライドし)、使用しているモデルに含めることができないことです。 . 問題は、クリーンなデザインの正しい方向を示すことであり、実装の詳細についてではありません。