我正在使用postgreSQL。需要范围以获取最近的带有punchlines_count的笑话。我已经在自己的范围内实现了这一目标。我需要知道的是,我的明细表计数器不应包含warn_level> 1的明细表。警告模型具有punchline_id和权重,权重== warn_level。请帮助我建立此查询。
说明:紧急情况警告可能带有权重1或2,也可能有2条警告,权重均为1。如果warn_level> 1,则不应将其计入我的范围。谢谢!
我的模特。
class Joke < ActiveRecord::Base
COLUMNS = self.column_names.map{|c| "jokes.#{c}" }.join(', ')
has_many :punchlines, :dependent => :destroy
scope :recent, :order => 'jokes.created_at DESC'
scope :recent_jokes_with_punchline_counter, lambda { |limit|
select("#{Joke::COLUMNS}, COUNT(punchlines.id) as punchlines_count").
joins(:punchlines).
group(Joke::COLUMNS).limit(limit) }
end
class Punchline < ActiveRecord::Base
belongs_to :joke
belongs_to :user
has_many :warns
end
class Warn < ActiveRecord::Base
belongs_to :punchline
belongs_to :user
end
架构:
create_table "jokes", :force => true do |t|
t.text "content"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "up_votes", :default => 0, :null => false
t.integer "down_votes", :default => 0, :null => false
t.string "cached_slug"
t.integer "popularity"
t.boolean "anonymous", :default => false
t.string "shorten_url"
end
create_table "punchlines", :force => true do |t|
t.text "content"
t.integer "user_id"
t.integer "joke_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "up_votes", :default => 0, :null => false
t.integer "down_votes", :default => 0, :null => false
t.string "cached_slug"
t.boolean "anonymous", :default => false
end
create_table "warns", :force => true do |t|
t.integer "punchline_id"
t.integer "user_id"
t.integer "weight"
end
end
最佳答案
我认为您最好通过在warn_level
上创建一个punchlines
字段来解决此问题。
就像ActiveRecord神奇地为您提供的counter
一样,我们可以做类似的事情。
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缓存为一列。
但是让它迭代处理。
关于sql - 构建复杂的Rails SQL,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7853141/