1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Merge pull request #7839 from chancancode/handle_aliased_attributes_in_ar_relation

Handle aliased attributes in AR::Relation
This commit is contained in:
Aaron Patterson 2013-05-01 17:59:24 -07:00
commit dd1f36078e
7 changed files with 70 additions and 9 deletions

View file

@ -1,3 +1,27 @@
* Handle aliased attributes in ActiveRecord::Relation.
When using symbol keys, ActiveRecord will now translate aliased attribute names to the actual column name used in the database:
With the model
class Topic
alias_attribute :heading, :title
end
The call
Topic.where(heading: 'The First Topic')
should yield the same result as
Topic.where(title: 'The First Topic')
This also applies to ActiveRecord::Relation::Calculations calls such as `Model.sum(:aliased)` and `Model.pluck(:aliased)`.
This will not work with SQL fragment strings like `Model.sum('DISTINCT aliased')`.
*Godfrey Chan*
* Mute `psql` output when running rake db:schema:load.
*Godfrey Chan*

View file

@ -27,7 +27,7 @@ module ActiveRecord
# Calculates the average value on a given column. Returns +nil+ if there's
# no row. See +calculate+ for examples with options.
#
# Person.average('age') # => 35.8
# Person.average(:age) # => 35.8
def average(column_name, options = {})
calculate(:average, column_name, options)
end
@ -36,7 +36,7 @@ module ActiveRecord
# with the same data type of the column, or +nil+ if there's no row. See
# +calculate+ for examples with options.
#
# Person.minimum('age') # => 7
# Person.minimum(:age) # => 7
def minimum(column_name, options = {})
calculate(:minimum, column_name, options)
end
@ -45,7 +45,7 @@ module ActiveRecord
# with the same data type of the column, or +nil+ if there's no row. See
# +calculate+ for examples with options.
#
# Person.maximum('age') # => 93
# Person.maximum(:age) # => 93
def maximum(column_name, options = {})
calculate(:maximum, column_name, options)
end
@ -54,7 +54,7 @@ module ActiveRecord
# with the same data type of the column, 0 if there's no row. See
# +calculate+ for examples with options.
#
# Person.sum('age') # => 4562
# Person.sum(:age) # => 4562
def sum(*args)
if block_given?
ActiveSupport::Deprecation.warn(
@ -101,6 +101,10 @@ module ActiveRecord
def calculate(operation, column_name, options = {})
relation = with_default_scope
if column_name.is_a?(Symbol) && attribute_aliases.key?(column_name.to_s)
column_name = attribute_aliases[column_name.to_s].to_sym
end
if relation.equal?(self)
if has_include?(column_name)
construct_relation_for_association_calculations.calculate(operation, column_name, options)
@ -149,11 +153,17 @@ module ActiveRecord
#
def pluck(*column_names)
column_names.map! do |column_name|
if column_name.is_a?(Symbol) && self.column_names.include?(column_name.to_s)
"#{connection.quote_table_name(table_name)}.#{connection.quote_column_name(column_name)}"
else
column_name
if column_name.is_a?(Symbol)
if attribute_aliases.key?(column_name.to_s)
column_name = attribute_aliases[column_name.to_s].to_sym
end
if self.columns_hash.key?(column_name.to_s)
column_name = "#{connection.quote_table_name(table_name)}.#{connection.quote_column_name(column_name)}"
end
end
column_name
end
if has_include?(column_names.first)

View file

@ -6,6 +6,10 @@ module ActiveRecord
attributes.each do |column, value|
table = default_table
if column.is_a?(Symbol) && klass.attribute_aliases.key?(column.to_s)
column = klass.attribute_aliases[column.to_s]
end
if value.is_a?(Hash)
if value.empty?
queries << '1=0'

View file

@ -28,6 +28,10 @@ class CalculationsTest < ActiveRecord::TestCase
assert_equal 53.0, value
end
def test_should_resolve_aliased_attributes
assert_equal 318, Account.sum(:available_credit)
end
def test_should_return_decimal_average_of_integer_field
value = Account.average(:id)
assert_equal 3.5, value
@ -352,6 +356,10 @@ class CalculationsTest < ActiveRecord::TestCase
assert_equal 4, Account.select(:credit_limit).uniq.count
end
def test_count_with_aliased_attribute
assert_equal 6, Account.count(:available_credit)
end
def test_count_with_column_and_options_parameter
assert_equal 2, Account.where("credit_limit = 50 AND firm_id IS NOT NULL").count(:firm_id)
end
@ -488,6 +496,10 @@ class CalculationsTest < ActiveRecord::TestCase
assert_equal [contract.id], company.contracts.pluck(:id)
end
def test_pluck_on_aliased_attribute
assert_equal 'The First Topic', Topic.order(:id).pluck(:heading).first
end
def test_pluck_with_serialization
t = Topic.create!(:content => { :foo => :bar })
assert_equal [{:foo => :bar}], Topic.where(:id => t.id).pluck(:content)

View file

@ -47,7 +47,8 @@ class FinderTest < ActiveRecord::TestCase
def test_exists
assert Topic.exists?(1)
assert Topic.exists?("1")
assert Topic.exists?(:author_name => "David")
assert Topic.exists?(title: "The First Topic")
assert Topic.exists?(heading: "The First Topic")
assert Topic.exists?(:author_name => "Mary", :approved => true)
assert Topic.exists?(["parent_id = ?", 1])
assert !Topic.exists?(45)

View file

@ -5,6 +5,7 @@ require 'models/treasure'
require 'models/post'
require 'models/comment'
require 'models/edge'
require 'models/topic'
module ActiveRecord
class WhereTest < ActiveRecord::TestCase
@ -80,6 +81,13 @@ module ActiveRecord
assert_equal expected.to_sql, actual.to_sql
end
def test_aliased_attribute
expected = Topic.where(heading: 'The First Topic')
actual = Topic.where(title: 'The First Topic')
assert_equal expected.to_sql, actual.to_sql
end
def test_where_error
assert_raises(ActiveRecord::StatementInvalid) do
Post.where(:id => { 'posts.author_id' => 10 }).first

View file

@ -206,6 +206,8 @@ class Account < ActiveRecord::Base
belongs_to :firm, :class_name => 'Company'
belongs_to :unautosaved_firm, :foreign_key => "firm_id", :class_name => "Firm", :autosave => false
alias_attribute :available_credit, :credit_limit
def self.destroyed_account_ids
@destroyed_account_ids ||= Hash.new { |h,k| h[k] = [] }
end