Я думаю, вам лучше подойти к этому, создав поле warn_level
на punchlines
.
Так же, как counter
, который магически дает вам ActiveRecord, мы можем сделать нечто подобное.
add_column :punchlines, :warn_level, :integer, :default => 0
class Punchline < ActiveRecord::Base
def update_warn_level!
self.update_attribute(:warn_level, self.warns.sum(:weight))
end
end
Когда добавляется предупреждение, вы можете вручную вызвать этот метод или сделать так, чтобы наблюдатель сделал это за вас.
http://guides.rubyonrails.org/active_record_validations_callbacks.html#observers
class WarnObserver < ActiveRecord::Observer
def after_create(model)
if model.punchline
model.punchline.update_warn_level!
end
end
end
# in your application.rb
config.active_record.observers = :warn_observer
После этого ваша проблема станет намного проще,
мы можем сделать то, что вы хотите с помощью следующего sql.
SELECT jobs.*, (
SELECT COUNT(*) FROM punchlines
WHERE punchlines.job_id = jobs.id
AND punchlines.warn_level <= 1
) AS punchline_count
Это можно выразить в ActiveRecord
PUNCHLINE_COUNT = <<-SQL
SELECT COUNT(*) FROM punchlines
WHERE punchlines.job_id = jobs.id
AND punchlines.warn_level <= 1
SQL
def with_punchline_count
select("jobs.*, (#{PUNCHLINE_COUNT}) AS punchline_count")
end
Это выглядит довольно грязно,
но я думаю, что вы поставили перед собой сложную проблему.
Надеюсь, это работает для вас.
Примечание: вы также можете кэшировать post_count как столбец, следуя аналогичному подходу.
Но давайте разберемся с этим итеративно.