At Discourse, we would like to have all the posts of a topic ordered by their post number by default. Basically, we want to have something like:
class Post < ActiveRecord::Base
belongs_to :topic
end
# == Schema Information
#
# Table name: posts
#
# id :integer not null, primary key
# topic_id :integer not null
# post_number :integer not null
class Topic < ActiveRecord::Base
has_many :posts, -> { order(:post_number) }
end
The problem is that because post_number
is unique for posts in same topic, any further order
s on posts
are useless. Let’s consider topic
to be an instance of Topic
, then topic.posts.order(:created_at)
will generate a clause ORDER BY post_number, created_at
.
One solution to this is to use reorder
instead of order
, however I consider that something one could forget and cause a couple of WTFs. Another solution is to use implicit_order_column = 'post_number'
, but this would break other things like Post.last
, which will no longer return the last created post, but the last post from the longest topic. What we would like to have is an implicit order for relations similar to implicit_order_column
.
I decided to implement a solution to this and added implicit_order
query method, which defines an implicit order which will be used if no other order is defined. Using it, the example above becomes:
class Topic < ActiveRecord::Base
has_many :posts, -> { implicit_order(:post_number) }
end
topic.posts # ORDER BY post_number
topic.posts.order(:created_at) # ORDER BY created_at
I believe that this could replace even implicit_order_column
if one would use default_scope
and implicit_order
together.
https://github.com/rails/rails/pull/39525
Sorry for being a bit late to the party.