提交 b09d6aae 编写于 作者: R Rafael Mendonça França

Merge pull request #7176 from bogdan/reverse_order

AR::Relation#order: make new order prepend old one.
## Rails 4.0.0 (unreleased) ## ## 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 * `Model.all` now returns an `ActiveRecord::Relation`, rather than an
array of records. Use `Model.to_a` or `Relation#to_a` if you really array of records. Use `Model.to_a` or `Relation#to_a` if you really
want an array. want an array.
......
...@@ -311,7 +311,7 @@ def find_first ...@@ -311,7 +311,7 @@ def find_first
@records.first @records.first
else else
@first ||= @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 order(arel_table[primary_key].asc).limit(1).to_a.first
else else
limit(1).to_a.first limit(1).to_a.first
......
...@@ -214,7 +214,7 @@ def order!(*args) ...@@ -214,7 +214,7 @@ def order!(*args)
references.map! { |arg| arg =~ /^([a-zA-Z]\w*)\.(\w+)/ && $1 }.compact! references.map! { |arg| arg =~ /^([a-zA-Z]\w*)\.(\w+)/ && $1 }.compact!
references!(references) if references.any? references!(references) if references.any?
self.order_values += args self.order_values = args + self.order_values
self self
end end
...@@ -226,7 +226,7 @@ def order!(*args) ...@@ -226,7 +226,7 @@ def order!(*args)
# #
# User.order('email DESC').reorder('id ASC').order('name ASC') # 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) def reorder(*args)
args.blank? ? self : spawn.reorder!(*args) args.blank? ? self : spawn.reorder!(*args)
end end
......
...@@ -513,9 +513,9 @@ def test_dynamic_find_should_respect_association_order ...@@ -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') assert_equal high_id_jamis, projects(:active_record).developers.find_by_name('Jamis')
end 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') 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 end
def test_dynamic_find_all_should_respect_readonly_access def test_dynamic_find_all_should_respect_readonly_access
......
...@@ -231,9 +231,9 @@ def test_find_many_with_merged_options ...@@ -231,9 +231,9 @@ def test_find_many_with_merged_options
assert_equal 2, companies(:first_firm).limited_clients.limit(nil).to_a.size assert_equal 2, companies(:first_firm).limited_clients.limit(nil).to_a.size
end 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') 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 end
def test_dynamic_find_should_respect_association_order def test_dynamic_find_should_respect_association_order
......
...@@ -385,7 +385,7 @@ def test_default_scope_with_multiple_calls ...@@ -385,7 +385,7 @@ def test_default_scope_with_multiple_calls
end end
def test_scope_overwrites_default 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 } received = DeveloperOrderedBySalary.by_name.to_a.collect { |dev| dev.name }
assert_equal expected, received assert_equal expected, received
end end
...@@ -397,13 +397,13 @@ def test_reorder_overrides_default_scope_order ...@@ -397,13 +397,13 @@ def test_reorder_overrides_default_scope_order
end end
def test_order_after_reorder_combines_orders 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] } received = Developer.order('name ASC').reorder('name DESC').order('id DESC').collect { |dev| [dev.name, dev.id] }
assert_equal expected, received assert_equal expected, received
end end
def test_order_in_default_scope_should_prevail def test_order_in_default_scope_should_not_prevail
expected = Developer.all.merge!(:order => 'salary desc').to_a.collect { |dev| dev.salary } expected = Developer.all.merge!(:order => 'salary').to_a.collect { |dev| dev.salary }
received = DeveloperOrderedBySalary.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 assert_equal expected, received
end end
......
...@@ -165,7 +165,7 @@ def test_finding_last_with_arel_order ...@@ -165,7 +165,7 @@ def test_finding_last_with_arel_order
end end
def test_finding_with_order_concatenated 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 4, topics.to_a.size
assert_equal topics(:fourth).title, topics.first.title assert_equal topics(:fourth).title, topics.first.title
end end
...@@ -1068,20 +1068,20 @@ def test_order_by_relation_attribute ...@@ -1068,20 +1068,20 @@ def test_order_by_relation_attribute
end end
def test_default_scope_order_with_scope_order def test_default_scope_order_with_scope_order
assert_equal 'zyke', CoolCar.order_using_new_style.limit(1).first.name assert_equal 'honda', CoolCar.order_using_new_style.limit(1).first.name
assert_equal 'zyke', FastCar.order_using_new_style.limit(1).first.name assert_equal 'honda', FastCar.order_using_new_style.limit(1).first.name
end end
def test_order_using_scoping def test_order_using_scoping
car1 = CoolCar.order('id DESC').scoping do car1 = CoolCar.order('id DESC').scoping do
CoolCar.all.merge!(:order => 'id asc').first CoolCar.all.merge!(:order => 'id asc').first
end end
assert_equal 'zyke', car1.name assert_equal 'honda', car1.name
car2 = FastCar.order('id DESC').scoping do car2 = FastCar.order('id DESC').scoping do
FastCar.all.merge!(:order => 'id asc').first FastCar.all.merge!(:order => 'id asc').first
end end
assert_equal 'zyke', car2.name assert_equal 'honda', car2.name
end end
def test_unscoped_block_style def test_unscoped_block_style
......
...@@ -492,7 +492,7 @@ This code will generate SQL like this: ...@@ -492,7 +492,7 @@ This code will generate SQL like this:
SELECT * FROM clients WHERE (clients.orders_count IN (1,3,5)) SELECT * FROM clients WHERE (clients.orders_count IN (1,3,5))
</sql> </sql>
h3. Ordering h3(#ordering). Ordering
To retrieve records from the database in a specific order, you can use the +order+ method. 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") ...@@ -518,6 +518,13 @@ Client.order("orders_count ASC, created_at DESC")
Client.order("orders_count ASC", "created_at DESC") Client.order("orders_count ASC", "created_at DESC")
</ruby> </ruby>
If you want to call +order+ multiple times e.g. in different context, new order will prepend previous one
<ruby>
Client.order("orders_count ASC").order("created_at DESC")
# SELECT * FROM clients ORDER BY created_at DESC, orders_count ASC
</ruby>
h3. Selecting Specific Fields h3. Selecting Specific Fields
By default, <tt>Model.find</tt> selects all the fields from the result set using +select *+. By default, <tt>Model.find</tt> selects all the fields from the result set using +select *+.
......
...@@ -42,6 +42,8 @@ h4(#active_record4_0). Active Record ...@@ -42,6 +42,8 @@ h4(#active_record4_0). Active Record
The <tt>delete</tt> method in collection associations can now receive <tt>Fixnum</tt> or <tt>String</tt> arguments as record ids, besides records, pretty much like the <tt>destroy</tt> method does. Previously it raised <tt>ActiveRecord::AssociationTypeMismatch</tt> for such arguments. From Rails 4.0 on <tt>delete</tt> automatically tries to find the records matching the given ids before deleting them. The <tt>delete</tt> method in collection associations can now receive <tt>Fixnum</tt> or <tt>String</tt> arguments as record ids, besides records, pretty much like the <tt>destroy</tt> method does. Previously it raised <tt>ActiveRecord::AssociationTypeMismatch</tt> for such arguments. From Rails 4.0 on <tt>delete</tt> 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 h4(#active_model4_0). Active Model
Rails 4.0 has changed how errors attach with the <tt>ActiveModel::Validations::ConfirmationValidator</tt>. Now when confirmation validations fail the error will be attached to <tt>:#{attribute}_confirmation</tt> instead of <tt>attribute</tt>. Rails 4.0 has changed how errors attach with the <tt>ActiveModel::Validations::ConfirmationValidator</tt>. Now when confirmation validations fail the error will be attached to <tt>:#{attribute}_confirmation</tt> instead of <tt>attribute</tt>.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册