rails: has_many ordering breaking when using :includes and join table in :where

Here’s the relevant code from my app

class Activity < ActiveRecord::Base
   scope :with_comments, includes(:comments=>:user)
   has_many :comments, :as=>:commentable, :order=>'created_at ASC'
end


irb(main):029:0> a = Activity.includes(:user).where(["users.privacy_level = ? OR users.privacy_level IS null", User::PRIVACY_PUBLIC]).where(:created_at=>(1.week.ago..Date.today.end_of_day)).where('comments_count > 5').with_comments.limit(10); 0
=> 0
irb(main):031:0> a.first.comments.each { |c| puts c.created_at };0
2012-06-13 18:38:36 UTC
2012-06-13 04:12:26 UTC
2012-06-12 14:49:29 UTC
2012-06-13 02:59:15 UTC
2012-06-13 02:46:14 UTC
2012-06-13 14:26:29 UTC

About this issue

  • Original URL
  • State: closed
  • Created 12 years ago
  • Reactions: 2
  • Comments: 27 (9 by maintainers)

Most upvoted comments

Any news on this issue?

This is still an issue and should be reopened.

I made a comprehensive gist to test different loading strategies (eager_load, includes, includes & references, includes & preload): https://gist.github.com/thisismydesign/b08ba0ee3c1862ef87effe0e25386267

Given the following example

class User < ActiveRecord::Base
  has_many :likes, as: :liker
end

class Activity < ActiveRecord::Base
  has_many :likes, as: :likable
end

class Like < ActiveRecord::Base
  belongs_to :likable, polymorphic: true
  belongs_to :liker, polymorphic: true

  default_scope { order(created_at: :asc) }
end

I wanted to add a first_like association to Activity and load it without N+1.

You can see in the gist that the only working approach is:

class Activity < ActiveRecord::Base
  # ...
  has_one :first_like, -> { order(created_at: :asc) }, class_name: "Like", as: :likable
end

Activity.includes(:first_like).preload(:first_like)

includes on its own can decide whether to do join or an additional query. preload, eager_load and references force one or the other approach. preload forces an additional query which is the working approach for ordered associations. Using includes by itself will not work in every case!

An additional issue I ran into was using .limit(n) in the association scope which breaks ordering and also the whole association with some approaches. You can test using the gist.

This problem still exists in 4-1-stable. A workaround is to use preload instead of includes which causes Rails to create second query to fetch the associated objects, respecting the order specified on the association, rather than creating a single query with joins.

Noticed this “bug” in the production environment, switching to preload didn’t help. Looking for other options.

This issue is still exists with activesupport 6.1.3.2.

Any news? It seems to be the same in Rails 5.0.6…