Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

has_many through obeys order on through association #10087

Merged
merged 1 commit into from

3 participants

@neerajdotname
Collaborator

fixes #10016

activerecord/CHANGELOG.md
@@ -1,5 +1,10 @@
## Rails 4.0.0 (unreleased) ##
+* has_many using :through now obyes the order clause mentioned in

Typo: obeys

Also, it might be good to put has_many and :through inside backticks for better formatting.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
activerecord/CHANGELOG.md
@@ -1,5 +1,10 @@
## Rails 4.0.0 (unreleased) ##
+* has_many using :through now obyes the order clause mentioned in
+ through association. Fixes #10016

. at the end.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...es/associations/has_many_through_associations_test.rb
@@ -882,6 +882,10 @@ def test_has_many_through_with_polymorphic_source
assert_equal [tags(:general)], post.reload.tags
end
+ def test_has_many_through_obeys_order_on_through_association
+ assert Owner.first.toys.to_sql.include?("pets.name desc")

Can we actually test that records are coming back ordered? I'm afraid this could lead to false positives in the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@egilburg

Would this cause issues if there are no explicit table name specified and both tables have the same column name? E.g. both just say "order by name". Both orders would be unambiguous on their own, but could ambiguous when joined automatically.

@neerajdotname
Collaborator

@egilburg this is what I found.

class Physician < ActiveRecord::Base
  has_many :appointments, -> { order 'id desc' }
  has_many :patients, -> { order 'id asc' }, through: :appointments
end

$ Physician.first.patients.to_a
#=> SELECT "patients".* FROM "patients" INNER JOIN "appointments" ON "patients"."id" = 
"appointments"."patient_id" WHERE "appointments"."physician_id" = ? ORDER BY id asc, id desc 
 [["physician_id", 42]]

I tested that sql in sqlite3, mysql2 and pg . And it worked ok.

@neerajdotname
Collaborator

@carlosantoniodasilva Please take a look. Thanks.

...es/associations/has_many_through_associations_test.rb
@@ -882,6 +882,11 @@ def test_has_many_through_with_polymorphic_source
assert_equal [tags(:general)], post.reload.tags
end
+ def test_has_many_through_obeys_order_on_through_association
+ assert Owner.first.toys.to_sql.include?("pets.name desc")
+ assert_equal ["parrot", "bulbul"], owners(:blackbeard).toys.map { |r| r.pet.name }

Are owners(:blackbeard) and Owner.first the same? Perhaps the first line could use the fixture as well to avoid an extra query.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@carlosantoniodasilva

@neerajdotname looks good, just a minor comment.

@neerajdotname
Collaborator

@carlosantoniodasilva good catch. Fixed.

@carlosantoniodasilva carlosantoniodasilva merged commit ba4c274 into rails:master
@carlosantoniodasilva

Thanks!

@egilburg egilburg commented on the diff
...d/lib/active_record/associations/association_scope.rb
@@ -101,6 +101,7 @@ def add_constraints(scope)
scope.includes! item.includes_values
scope.where_values += item.where_values
+ scope.order_values += (item.order_values - scope.order_values)
@egilburg
egilburg added a note

belated notice, but i think this line is equivalent to simplified:

scope.order_values |= item.order_values

note |= rather than ||=

@neerajdotname Collaborator

@egilburg good call. That is much more intent revealing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Apr 4, 2013
  1. @neerajdotname
This page is out of date. Refresh to see the latest.
View
5 activerecord/CHANGELOG.md
@@ -1,5 +1,10 @@
## Rails 4.0.0 (unreleased) ##
+* `has_many` using `:through` now obeys the order clause mentioned in
+ through association. Fixes #10016.
+
+ *Neeraj Singh*
+
* `belongs_to :touch` behavior now touches old association when
transitioning to new association.
View
1  activerecord/lib/active_record/associations/association_scope.rb
@@ -101,6 +101,7 @@ def add_constraints(scope)
scope.includes! item.includes_values
scope.where_values += item.where_values
+ scope.order_values += (item.order_values - scope.order_values)
@egilburg
egilburg added a note

belated notice, but i think this line is equivalent to simplified:

scope.order_values |= item.order_values

note |= rather than ||=

@neerajdotname Collaborator

@egilburg good call. That is much more intent revealing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
end
end
View
2  activerecord/test/cases/associations/eager_test.rb
@@ -302,7 +302,7 @@ def test_nested_loading_through_has_one_association_with_conditions_on_nested_as
def test_eager_association_loading_with_belongs_to_and_foreign_keys
pets = Pet.all.merge!(:includes => :owner).to_a
- assert_equal 3, pets.length
+ assert_equal 4, pets.length
end
def test_eager_association_loading_with_belongs_to
View
8 activerecord/test/cases/associations/has_many_through_associations_test.rb
@@ -583,7 +583,7 @@ def test_has_many_association_through_a_belongs_to_association
end
def test_has_many_association_through_a_has_many_association_with_nonstandard_primary_keys
- assert_equal 1, owners(:blackbeard).toys.count
+ assert_equal 2, owners(:blackbeard).toys.count
end
def test_find_on_has_many_association_collection_with_include_and_conditions
@@ -882,6 +882,12 @@ def test_has_many_through_with_polymorphic_source
assert_equal [tags(:general)], post.reload.tags
end
+ def test_has_many_through_obeys_order_on_through_association
+ owner = owners(:blackbeard)
+ assert owner.toys.to_sql.include?("pets.name desc")
+ assert_equal ["parrot", "bulbul"], owner.toys.map { |r| r.pet.name }
+ end
+
test "has many through associations on new records use null relations" do
person = Person.new
View
5 activerecord/test/fixtures/pets.yml
@@ -12,3 +12,8 @@ mochi:
pet_id: 3
name: mochi
owner_id: 2
+
+bulbul:
+ pet_id: 4
+ name: bulbul
+ owner_id: 1
View
6 activerecord/test/fixtures/toys.yml
@@ -2,7 +2,13 @@ bone:
toy_id: 1
name: Bone
pet_id: 1
+
doll:
toy_id: 2
name: Doll
pet_id: 2
+
+bulbuli:
+ toy_id: 3
+ name: Bulbuli
+ pet_id: 4
View
2  activerecord/test/models/owner.rb
@@ -1,5 +1,5 @@
class Owner < ActiveRecord::Base
self.primary_key = :owner_id
- has_many :pets
+ has_many :pets, -> { order 'pets.name desc' }
has_many :toys, :through => :pets
end
Something went wrong with that request. Please try again.