Ruby on rails Rails按属性排序,然后在PG数据库中按特定的子属性排序
我正在Rails 4中构建一个论坛,并尝试实现粘性主题功能。布尔值的粘性属性是主题表中的一列。我有一些用户可选择的排序选项,默认排序是按最新消息的创建时间排序。但是,具有sticky属性的主题应优先排序,因此应首先列出sticky主题,然后列出包含最新消息的主题,然后列出包含第二条最新消息的主题,以此类推 一个主题有许多消息,而一条消息属于一个主题Ruby on rails Rails按属性排序,然后在PG数据库中按特定的子属性排序,ruby-on-rails,postgresql,sorting,Ruby On Rails,Postgresql,Sorting,我正在Rails 4中构建一个论坛,并尝试实现粘性主题功能。布尔值的粘性属性是主题表中的一列。我有一些用户可选择的排序选项,默认排序是按最新消息的创建时间排序。但是,具有sticky属性的主题应优先排序,因此应首先列出sticky主题,然后列出包含最新消息的主题,然后列出包含第二条最新消息的主题,以此类推 一个主题有许多消息,而一条消息属于一个主题 class Topic < ActiveRecord::Base ... has_many :messages, -> { o
class Topic < ActiveRecord::Base
...
has_many :messages, -> { order(:created_at) }, dependent: :destroy
...
scope :sort_by_latest_message, -> { includes(:messages).order("messages.created_at DESC") }
scope :sort_by_sticky, -> { order("sticky DESC") }
scope :sort_by_created_at, -> { order("created_at DESC") } # This one works, but I'm putting it here for reference.
...
end
这会导致错误:
PG::GroupingError:ERROR:列topics.id必须出现在
GROUP BY子句或GROUP BY子句可用于聚合函数中
我从其他问题中读到,我认为我可能需要一个有选择的电话来实现这一点,但我不清楚在这种情况下这应该属于什么
我使用了基于params散列的各种过滤器,但最终,我尝试在PG数据库中使用Topic.sort_by_sticky.sort_by_latest_消息这样的调用。Topic.sort_by_sticky.sort_by_created_at工作正常,因此我的问题似乎是当我想按主题上的一个属性排序,然后按子级上的一个属性排序,特别是最后一个子级的创建值排序
更新
我注意到,最初的错误主要发生在我应用另一个过滤器按标记过滤时。一个主题通过标记有许多标记
scope :tag_filter, ->(tag_ids) { joins(:tags).where("tag_id IN (?)", tag_ids).uniq }
这来自主题模型中包含的模块
但是,根据一些建议,我取消了:sort_by_latest_消息范围,而是创建了一个具有类似逻辑的类方法,但始终包含粘性属性中的因素:
def self.default_sort
results = self.includes(:messages).sort_by_sticky.order("messages.created_at DESC")
results
end
实际上,我不清楚includes如何确定我想要使用任何主题的最后一条消息,但这似乎是可行的。我不确定如何在二阶调用中使用散列,但我已更新:sort_by_stick_order使用散列符号而不是字符串:
scope :sort_by_sticky, -> { order(sticky: :desc) }
更新2
发布此问题后,我已更改了几次设置。首先,我使用以下方法来实现按最新消息排序,而不是按作用域排序:
def self.sort_by_latest_message
Topic.all.sort_by { |topic| topic.latest_message.created_at }.reverse
end
def latest_message
messages.sort_by(&:created_at).last
end
然而,这似乎相当低效,我怀疑这将逐渐成为一个有大量主题和信息的更大问题
因此,我目前正在通过消息模型上的以下回调在每个主题的列上维护最新的消息:
class Message < ActiveRecord::Base
...
belongs_to :topic
...
after_save :update_topic_latest_message_at, on: :create
...
private
def update_topic_latest_message_at
self.topic.update_attribute(:latest_message_at, self.created_at) # No validation performed
end
end
有根据的猜测很可能是错误的:我不认为阿雷尔会用文本条款来连锁订单。尝试ordersticky::desc和simlar需要Rails和Arel4。另一种真正应该起作用的方法是放弃作用域并传递散列顺序。看维塔利在这一点上的评论。这似乎为我指明了正确的方向,我更新了原始问题,以反映我所做的更改。对于如何更好地工作,我仍然有一些问题:includes call如何知道我想要任何主题的最后一条消息。。。可以指定另一个吗?如果可以将DESC中创建的ordermessages.created_转换为我所做的散列:sort_by_sticky。但我已经将更改推到了生产环境中,错误还没有再次出现。非常感谢。通常在Arel中,字符串和符号是可互换的。所以我会尝试{'messages.created'=>:desc}长镜头应该是{[messages:,created:]=>:desc}或者同样长的{{{messages::created}=>:desc}。但也许你会幸运的。
class Message < ActiveRecord::Base
...
belongs_to :topic
...
after_save :update_topic_latest_message_at, on: :create
...
private
def update_topic_latest_message_at
self.topic.update_attribute(:latest_message_at, self.created_at) # No validation performed
end
end