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:
commit
dd1f36078e
7 changed files with 70 additions and 9 deletions
|
@ -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*
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue