diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 5f3b2eaf7ccb342ed3832e72cdbe2cab6856bb93..00bc45e4cc7f9a3e920e0985eb38a5e4f8b0f75d 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,5 +1,14 @@ ## Rails 4.0.0 (unreleased) ## +* AR::Relation#order: make new order prepend old one. + + User.order("name asc").order("created_at desc") + # SELECT * FROM users ORDER BY created_at desc, name asc + + This also affects order defined in `default_scope` or any kind of associations. + + *Bogdan Gusiev* + * `Model.all` now returns an `ActiveRecord::Relation`, rather than an array of records. Use `Model.to_a` or `Relation#to_a` if you really want an array. diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index c01aed2d8e0ed1fa2b17706d833150439bf85686..97c3db683f1eedd1edcb46807be88a332c7ddc3d 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -311,7 +311,7 @@ def find_first @records.first else @first ||= - if order_values.empty? && primary_key + if with_default_scope.order_values.empty? && primary_key order(arel_table[primary_key].asc).limit(1).to_a.first else limit(1).to_a.first diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 94db2846f30e1c9d677ef4ad064d25034992fd8e..967b82aeb92f5f4775692e3d217a0872bae158c4 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -214,7 +214,7 @@ def order!(*args) references.map! { |arg| arg =~ /^([a-zA-Z]\w*)\.(\w+)/ && $1 }.compact! references!(references) if references.any? - self.order_values += args + self.order_values = args + self.order_values self end @@ -226,7 +226,7 @@ def order!(*args) # # User.order('email DESC').reorder('id ASC').order('name ASC') # - # generates a query with 'ORDER BY id ASC, name ASC'. + # generates a query with 'ORDER BY name ASC, id ASC'. def reorder(*args) args.blank? ? self : spawn.reorder!(*args) end diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb index a9e18dd8feef4429c3c7585ffbba7ad15a3d4c8a..e48ac845924955c27941740dc08b57bb68a209b4 100644 --- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb @@ -513,9 +513,9 @@ def test_dynamic_find_should_respect_association_order assert_equal high_id_jamis, projects(:active_record).developers.find_by_name('Jamis') end - def test_find_should_append_to_association_order + def test_find_should_prepend_to_association_order ordered_developers = projects(:active_record).developers.order('projects.id') - assert_equal ['developers.name desc, developers.id desc', 'projects.id'], ordered_developers.order_values + assert_equal ['projects.id', 'developers.name desc, developers.id desc'], ordered_developers.order_values end def test_dynamic_find_all_should_respect_readonly_access diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 6122104335e9f4817081a15c3873014d8296d7d8..6b675d3d54883d94454c1be736e6137d3dcc4d1a 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -231,9 +231,9 @@ def test_find_many_with_merged_options assert_equal 2, companies(:first_firm).limited_clients.limit(nil).to_a.size end - def test_find_should_append_to_association_order + def test_find_should_prepend_to_association_order ordered_clients = companies(:first_firm).clients_sorted_desc.order('companies.id') - assert_equal ['id DESC', 'companies.id'], ordered_clients.order_values + assert_equal ['companies.id', 'id DESC'], ordered_clients.order_values end def test_dynamic_find_should_respect_association_order diff --git a/activerecord/test/cases/relation_scoping_test.rb b/activerecord/test/cases/relation_scoping_test.rb index ba77bdcc8bbb8ad7f03c976dd827b25fe9759873..ef9905da2ecfcd2b54fd4ec653cd56a6ab17f38c 100644 --- a/activerecord/test/cases/relation_scoping_test.rb +++ b/activerecord/test/cases/relation_scoping_test.rb @@ -385,7 +385,7 @@ def test_default_scope_with_multiple_calls end def test_scope_overwrites_default - expected = Developer.all.merge!(:order => 'salary DESC, name DESC').to_a.collect { |dev| dev.name } + expected = Developer.all.merge!(:order => ' name DESC, salary DESC').to_a.collect { |dev| dev.name } received = DeveloperOrderedBySalary.by_name.to_a.collect { |dev| dev.name } assert_equal expected, received end @@ -397,13 +397,13 @@ def test_reorder_overrides_default_scope_order end def test_order_after_reorder_combines_orders - expected = Developer.order('name DESC, id DESC').collect { |dev| [dev.name, dev.id] } + expected = Developer.order('id DESC, name DESC').collect { |dev| [dev.name, dev.id] } received = Developer.order('name ASC').reorder('name DESC').order('id DESC').collect { |dev| [dev.name, dev.id] } assert_equal expected, received end - def test_order_in_default_scope_should_prevail - expected = Developer.all.merge!(:order => 'salary desc').to_a.collect { |dev| dev.salary } + def test_order_in_default_scope_should_not_prevail + expected = Developer.all.merge!(:order => 'salary').to_a.collect { |dev| dev.salary } received = DeveloperOrderedBySalary.all.merge!(:order => 'salary').to_a.collect { |dev| dev.salary } assert_equal expected, received end diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 9c64cb35e455c4b595f5bf3a0ec9d65e6418593a..4aa1977cf92e83e8a0b2b1ccc18408e3a30bc3a5 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -165,7 +165,7 @@ def test_finding_last_with_arel_order end def test_finding_with_order_concatenated - topics = Topic.order('author_name').order('title') + topics = Topic.order('title').order('author_name') assert_equal 4, topics.to_a.size assert_equal topics(:fourth).title, topics.first.title end @@ -1068,20 +1068,20 @@ def test_order_by_relation_attribute end def test_default_scope_order_with_scope_order - assert_equal 'zyke', CoolCar.order_using_new_style.limit(1).first.name - assert_equal 'zyke', FastCar.order_using_new_style.limit(1).first.name + assert_equal 'honda', CoolCar.order_using_new_style.limit(1).first.name + assert_equal 'honda', FastCar.order_using_new_style.limit(1).first.name end def test_order_using_scoping car1 = CoolCar.order('id DESC').scoping do CoolCar.all.merge!(:order => 'id asc').first end - assert_equal 'zyke', car1.name + assert_equal 'honda', car1.name car2 = FastCar.order('id DESC').scoping do FastCar.all.merge!(:order => 'id asc').first end - assert_equal 'zyke', car2.name + assert_equal 'honda', car2.name end def test_unscoped_block_style diff --git a/guides/source/active_record_querying.textile b/guides/source/active_record_querying.textile index b13932e8cb7f18ae6f09c24cfa481dceb501a4e1..dff829a4c1867b30cdab7798afe7ac83bac297c1 100644 --- a/guides/source/active_record_querying.textile +++ b/guides/source/active_record_querying.textile @@ -492,7 +492,7 @@ This code will generate SQL like this: SELECT * FROM clients WHERE (clients.orders_count IN (1,3,5)) -h3. Ordering +h3(#ordering). Ordering To retrieve records from the database in a specific order, you can use the +order+ method. @@ -518,6 +518,13 @@ Client.order("orders_count ASC, created_at DESC") Client.order("orders_count ASC", "created_at DESC") +If you want to call +order+ multiple times e.g. in different context, new order will prepend previous one + + +Client.order("orders_count ASC").order("created_at DESC") +# SELECT * FROM clients ORDER BY created_at DESC, orders_count ASC + + h3. Selecting Specific Fields By default, Model.find selects all the fields from the result set using +select *+. diff --git a/guides/source/upgrading_ruby_on_rails.textile b/guides/source/upgrading_ruby_on_rails.textile index 4bf47511270a8d66eaee83f6dc36efaacfcba666..5024bc4c373409c4e310f8ff37fdd2b1f9279c20 100644 --- a/guides/source/upgrading_ruby_on_rails.textile +++ b/guides/source/upgrading_ruby_on_rails.textile @@ -42,6 +42,8 @@ h4(#active_record4_0). Active Record The delete method in collection associations can now receive Fixnum or String arguments as record ids, besides records, pretty much like the destroy method does. Previously it raised ActiveRecord::AssociationTypeMismatch for such arguments. From Rails 4.0 on delete automatically tries to find the records matching the given ids before deleting them. +Rails 4.0 has changed how orders get stacked in +ActiveRecord::Relation+. In previous versions of rails new order was applied after previous defined order. But this is no long true. Check "ActiveRecord Query guide":active_record_querying.html#ordering for more information. + h4(#active_model4_0). Active Model Rails 4.0 has changed how errors attach with the ActiveModel::Validations::ConfirmationValidator. Now when confirmation validations fail the error will be attached to :#{attribute}_confirmation instead of attribute.