diff options
Diffstat (limited to 'activerecord')
27 files changed, 224 insertions, 490 deletions
diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb index 2463f3951f..77971973f6 100644 --- a/activerecord/lib/active_record.rb +++ b/activerecord/lib/active_record.rb @@ -105,7 +105,6 @@ module ActiveRecord autoload :TimeZoneConversion autoload :Write autoload :Serialization - autoload :DeprecatedUnderscoreRead end end diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb index 861dda618a..7887d59aad 100644 --- a/activerecord/lib/active_record/associations/association.rb +++ b/activerecord/lib/active_record/associations/association.rb @@ -230,13 +230,8 @@ module ActiveRecord end def build_record(attributes, options) - attributes = (attributes || {}).reverse_merge(creation_attributes) - reflection.build_association(attributes, options) do |record| - record.assign_attributes( - create_scope.except(*record.changed), - :without_protection => true - ) + record.assign_attributes(create_scope.except(*record.changed), :without_protection => true) end end end diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index 650fa3fc42..237343c252 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -16,7 +16,6 @@ module ActiveRecord include TimeZoneConversion include Dirty include Serialization - include DeprecatedUnderscoreRead # Returns the value of the attribute identified by <tt>attr_name</tt> after it has been typecast (for example, # "2004-12-12" in a data column is cast to a date object, like Date.new(2004, 12, 12)). @@ -35,48 +34,26 @@ module ActiveRecord # accessors, mutators and query methods. def define_attribute_methods return if attribute_methods_generated? - - if base_class == self - super(column_names) - @attribute_methods_generated = true - else - base_class.define_attribute_methods - end + superclass.define_attribute_methods unless self == base_class + super(column_names) + @attribute_methods_generated = true end def attribute_methods_generated? - if base_class == self - @attribute_methods_generated ||= false - else - base_class.attribute_methods_generated? - end - end - - def generated_attribute_methods - @generated_attribute_methods ||= (base_class == self ? super : base_class.generated_attribute_methods) + @attribute_methods_generated ||= false end + # We will define the methods as instance methods, but will call them as singleton + # methods. This allows us to use method_defined? to check if the method exists, + # which is fast and won't give any false positives from the ancestors (because + # there are no ancestors). def generated_external_attribute_methods - @generated_external_attribute_methods ||= begin - if base_class == self - # We will define the methods as instance methods, but will call them as singleton - # methods. This allows us to use method_defined? to check if the method exists, - # which is fast and won't give any false positives from the ancestors (because - # there are no ancestors). - Module.new { extend self } - else - base_class.generated_external_attribute_methods - end - end + @generated_external_attribute_methods ||= Module.new { extend self } end def undefine_attribute_methods - if base_class == self - super - @attribute_methods_generated = false - else - base_class.undefine_attribute_methods - end + super + @attribute_methods_generated = false end def instance_method_already_implemented?(method_name) @@ -84,19 +61,32 @@ module ActiveRecord raise DangerousAttributeError, "#{method_name} is defined by ActiveRecord" end - super + if superclass == Base + super + else + method_defined_within?(method_name, superclass, superclass.generated_attribute_methods) || super + end end # A method name is 'dangerous' if it is already defined by Active Record, but # not by any ancestors. (So 'puts' is not dangerous but 'save' is.) - def dangerous_attribute_method?(method_name) - active_record = ActiveRecord::Base - superclass = ActiveRecord::Base.superclass - - (active_record.method_defined?(method_name) || - active_record.private_method_defined?(method_name)) && - !superclass.method_defined?(method_name) && - !superclass.private_method_defined?(method_name) + def dangerous_attribute_method?(name) + method_defined_within?(name, Base) + end + + # Note that we could do this via klass.instance_methods(false), but this would require us + # to maintain a cached Set (for speed) and invalidate it at the correct time, which would + # be a pain. This implementation is also O(1) while avoiding maintaining a cached Set. + def method_defined_within?(name, klass, sup = klass.superclass) + if klass.method_defined?(name) || klass.private_method_defined?(name) + if sup.method_defined?(name) || sup.private_method_defined?(name) + klass.instance_method(name).owner != sup.instance_method(name).owner + else + true + end + else + false + end end def attribute_method?(attribute) diff --git a/activerecord/lib/active_record/attribute_methods/deprecated_underscore_read.rb b/activerecord/lib/active_record/attribute_methods/deprecated_underscore_read.rb deleted file mode 100644 index 0eb0db65b1..0000000000 --- a/activerecord/lib/active_record/attribute_methods/deprecated_underscore_read.rb +++ /dev/null @@ -1,32 +0,0 @@ -require 'active_support/concern' -require 'active_support/deprecation' - -module ActiveRecord - module AttributeMethods - module DeprecatedUnderscoreRead - extend ActiveSupport::Concern - - included do - attribute_method_prefix "_" - end - - module ClassMethods - protected - - def define_method__attribute(attr_name) - # Do nothing, let it hit method missing instead. - end - end - - protected - - def _attribute(attr_name) - ActiveSupport::Deprecation.warn( - "You have called '_#{attr_name}'. This is deprecated. Please use " \ - "either '#{attr_name}' or read_attribute('#{attr_name}')." - ) - read_attribute(attr_name) - end - end - end -end diff --git a/activerecord/lib/active_record/attribute_methods/primary_key.rb b/activerecord/lib/active_record/attribute_methods/primary_key.rb index 5d37088d98..a7785f8786 100644 --- a/activerecord/lib/active_record/attribute_methods/primary_key.rb +++ b/activerecord/lib/active_record/attribute_methods/primary_key.rb @@ -80,10 +80,6 @@ module ActiveRecord end end - def original_primary_key #:nodoc: - deprecated_original_property_getter :primary_key - end - # Sets the name of the primary key column. # # class Project < ActiveRecord::Base @@ -103,11 +99,6 @@ module ActiveRecord @primary_key = value && value.to_s @quoted_primary_key = nil end - - def set_primary_key(value = nil, &block) #:nodoc: - deprecated_property_setter :primary_key, value, block - @quoted_primary_key = nil - end end end end diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb index 77bf9d0905..1548114580 100644 --- a/activerecord/lib/active_record/attribute_methods/read.rb +++ b/activerecord/lib/active_record/attribute_methods/read.rb @@ -30,15 +30,33 @@ module ActiveRecord end def undefine_attribute_methods - if base_class == self - generated_external_attribute_methods.module_eval do - instance_methods.each { |m| undef_method(m) } - end + generated_external_attribute_methods.module_eval do + instance_methods.each { |m| undef_method(m) } end super end + def type_cast_attribute(attr_name, attributes, cache = {}) #:nodoc: + return unless attr_name + attr_name = attr_name.to_s + + if generated_external_attribute_methods.method_defined?(attr_name) + if attributes.has_key?(attr_name) || attr_name == 'id' + generated_external_attribute_methods.send(attr_name, attributes[attr_name], attributes, cache, attr_name) + end + elsif !attribute_methods_generated? + # If we haven't generated the caster methods yet, do that and + # then try again + define_attribute_methods + type_cast_attribute(attr_name, attributes, cache) + else + # If we get here, the attribute has no associated DB column, so + # just return it verbatim. + attributes[attr_name] + end + end + protected # We want to generate the methods via module_eval rather than define_method, # because define_method is slower on dispatch and uses more memory (because it @@ -105,25 +123,7 @@ module ActiveRecord # Returns the value of the attribute identified by <tt>attr_name</tt> after it has been typecast (for example, # "2004-12-12" in a data column is cast to a date object, like Date.new(2004, 12, 12)). def read_attribute(attr_name) - return unless attr_name - - attr_name = attr_name.to_s - methods = self.class.generated_external_attribute_methods - - if methods.method_defined?(attr_name) - if @attributes.has_key?(attr_name) || attr_name == 'id' - methods.send(attr_name, @attributes[attr_name], @attributes, @attributes_cache, attr_name) - end - elsif !self.class.attribute_methods_generated? - # If we haven't generated the caster methods yet, do that and - # then try again - self.class.define_attribute_methods - read_attribute(attr_name) - else - # If we get here, the attribute has no associated DB column, so - # just return it verbatim. - @attributes[attr_name] - end + self.class.type_cast_attribute(attr_name, @attributes, @attributes_cache) end private diff --git a/activerecord/lib/active_record/attribute_methods/serialization.rb b/activerecord/lib/active_record/attribute_methods/serialization.rb index 0a4432506f..2ffd91f796 100644 --- a/activerecord/lib/active_record/attribute_methods/serialization.rb +++ b/activerecord/lib/active_record/attribute_methods/serialization.rb @@ -58,6 +58,18 @@ module ActiveRecord self.serialized_attributes = serialized_attributes.merge(attr_name.to_s => coder) end + def initialize_attributes(attributes) #:nodoc: + super + + serialized_attributes.each do |key, coder| + if attributes.key?(key) + attributes[key] = Attribute.new(coder, attributes[key], :serialized) + end + end + + attributes + end + private def attribute_cast_code(attr_name) @@ -69,14 +81,6 @@ module ActiveRecord end end - def set_serialized_attributes - self.class.serialized_attributes.each do |key, coder| - if @attributes.key?(key) - @attributes[key] = Attribute.new(coder, @attributes[key], :serialized) - end - end - end - def type_cast_attribute_for_write(column, value) if column && coder = self.class.serialized_attributes[column.name] Attribute.new(coder, value, :unserialized) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 432a40ea54..6a6f463ddd 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -469,7 +469,7 @@ module ActiveRecord #:nodoc: # # Instantiates a single new object bypassing mass-assignment security # User.new({ :first_name => 'Jamie', :is_admin => true }, :without_protection => true) def initialize(attributes = nil, options = {}) - @attributes = attributes_from_column_definition + @attributes = self.class.initialize_attributes(self.class.column_defaults.dup) @association_cache = {} @aggregation_cache = {} @attributes_cache = {} @@ -482,7 +482,6 @@ module ActiveRecord #:nodoc: @relation = nil ensure_proper_type - set_serialized_attributes populate_with_current_scope_attributes @@ -503,11 +502,9 @@ module ActiveRecord #:nodoc: # post.init_with('attributes' => { 'title' => 'hello world' }) # post.title # => 'hello world' def init_with(coder) - @attributes = coder['attributes'] + @attributes = self.class.initialize_attributes(coder['attributes']) @relation = nil - set_serialized_attributes - @attributes_cache, @previously_changed, @changed_attributes = {}, {}, {} @association_cache = {} @aggregation_cache = {} @@ -534,7 +531,7 @@ module ActiveRecord #:nodoc: _run_after_initialize_callbacks if respond_to?(:_run_after_initialize_callbacks) @changed_attributes = {} - attributes_from_column_definition.each do |attr, orig_value| + self.class.column_defaults.each do |attr, orig_value| @changed_attributes[attr] = orig_value if field_changed?(attr, orig_value, @attributes[attr]) end @@ -548,15 +545,6 @@ module ActiveRecord #:nodoc: super end - # Backport dup from 1.9 so that initialize_dup() gets called - unless Object.respond_to?(:initialize_dup) - def dup # :nodoc: - copy = super - copy.initialize_dup(self) - copy - end - end - # Populate +coder+ with attributes about this record that should be # serialized. The structure of +coder+ defined in this method is # guaranteed to match the structure of +coder+ passed to the +init_with+ diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb index 698da34d26..401398c56b 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -162,34 +162,6 @@ module ActiveRecord end end - def columns - with_connection do |c| - c.schema_cache.columns - end - end - deprecate :columns - - def columns_hash - with_connection do |c| - c.schema_cache.columns_hash - end - end - deprecate :columns_hash - - def primary_keys - with_connection do |c| - c.schema_cache.primary_keys - end - end - deprecate :primary_keys - - def clear_cache! - with_connection do |c| - c.schema_cache.clear! - end - end - deprecate :clear_cache! - # Return any checked-out connections back to the pool by threads that # are no longer alive. def clear_stale_cached_connections! diff --git a/activerecord/lib/active_record/identity_map.rb b/activerecord/lib/active_record/identity_map.rb index b15b5a8133..680d9ffea0 100644 --- a/activerecord/lib/active_record/identity_map.rb +++ b/activerecord/lib/active_record/identity_map.rb @@ -111,13 +111,12 @@ module ActiveRecord # model object. def reinit_with(coder) @attributes_cache = {} - dirty = @changed_attributes.keys - @attributes.update(coder['attributes'].except(*dirty)) + dirty = @changed_attributes.keys + attributes = self.class.initialize_attributes(coder['attributes'].except(*dirty)) + @attributes.update(attributes) @changed_attributes.update(coder['attributes'].slice(*dirty)) @changed_attributes.delete_if{|k,v| v.eql? @attributes[k]} - set_serialized_attributes - run_callbacks :find self diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb index ce0a165660..27267c9d38 100644 --- a/activerecord/lib/active_record/locking/optimistic.rb +++ b/activerecord/lib/active_record/locking/optimistic.rb @@ -64,21 +64,6 @@ module ActiveRecord send(lock_col + '=', previous_lock_value + 1) end - def attributes_from_column_definition - result = self.class.column_defaults.dup - - # If the locking column has no default value set, - # start the lock version at zero. Note we can't use - # <tt>locking_enabled?</tt> at this point as - # <tt>@attributes</tt> may not have been initialized yet. - - if result.key?(self.class.locking_column) && lock_optimistically - result[self.class.locking_column] ||= 0 - end - - result - end - def update(attribute_names = @attributes.keys) #:nodoc: return super unless locking_enabled? return 0 if attribute_names.empty? @@ -144,26 +129,18 @@ module ActiveRecord lock_optimistically && columns_hash[locking_column] end + # Set the column to use for optimistic locking. Defaults to +lock_version+. def locking_column=(value) @original_locking_column = @locking_column if defined?(@locking_column) @locking_column = value.to_s end - # Set the column to use for optimistic locking. Defaults to +lock_version+. - def set_locking_column(value = nil, &block) - deprecated_property_setter :locking_column, value, block - end - # The version column used for optimistic locking. Defaults to +lock_version+. def locking_column reset_locking_column unless defined?(@locking_column) @locking_column end - def original_locking_column #:nodoc: - deprecated_original_property_getter :locking_column - end - # Quote the column name used for optimistic locking. def quoted_locking_column connection.quote_column_name(locking_column) @@ -180,6 +157,18 @@ module ActiveRecord counters = counters.merge(locking_column => 1) if locking_enabled? super end + + # If the locking column has no default value set, + # start the lock version at zero. Note we can't use + # <tt>locking_enabled?</tt> at this point as + # <tt>@attributes</tt> may not have been initialized yet. + def initialize_attributes(attributes) #:nodoc: + if attributes.key?(locking_column) && lock_optimistically + attributes[locking_column] ||= 0 + end + + attributes + end end end end diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb index 36417d89f7..1de820b3a6 100644 --- a/activerecord/lib/active_record/model_schema.rb +++ b/activerecord/lib/active_record/model_schema.rb @@ -105,10 +105,6 @@ module ActiveRecord @table_name end - def original_table_name #:nodoc: - deprecated_original_property_getter :table_name - end - # Sets the table name explicitly. Example: # # class Project < ActiveRecord::Base @@ -125,13 +121,6 @@ module ActiveRecord @relation = Relation.new(self, arel_table) end - def set_table_name(value = nil, &block) #:nodoc: - deprecated_property_setter :table_name, value, block - @quoted_table_name = nil - @arel_table = nil - @relation = Relation.new(self, arel_table) - end - # Returns a quoted version of the table name, used to construct SQL statements. def quoted_table_name @quoted_table_name ||= connection.quote_table_name(table_name) @@ -161,20 +150,12 @@ module ActiveRecord end end - def original_inheritance_column #:nodoc: - deprecated_original_property_getter :inheritance_column - end - # Sets the value of inheritance_column def inheritance_column=(value) @original_inheritance_column = inheritance_column @inheritance_column = value.to_s end - def set_inheritance_column(value = nil, &block) #:nodoc: - deprecated_property_setter :inheritance_column, value, block - end - def sequence_name if base_class == self @sequence_name ||= reset_sequence_name @@ -183,10 +164,6 @@ module ActiveRecord end end - def original_sequence_name #:nodoc: - deprecated_original_property_getter :sequence_name - end - def reset_sequence_name #:nodoc: self.sequence_name = connection.default_sequence_name(table_name, primary_key) end @@ -210,10 +187,6 @@ module ActiveRecord @sequence_name = value.to_s end - def set_sequence_name(value = nil, &block) #:nodoc: - deprecated_property_setter :sequence_name, value, block - end - # Indicates whether the table associated with this class exists def table_exists? connection.schema_cache.table_exists?(table_name) @@ -329,34 +302,6 @@ module ActiveRecord base.table_name end end - - def deprecated_property_setter(property, value, block) - if block - ActiveSupport::Deprecation.warn( - "Calling set_#{property} is deprecated. If you need to lazily evaluate " \ - "the #{property}, define your own `self.#{property}` class method. You can use `super` " \ - "to get the default #{property} where you would have called `original_#{property}`." - ) - - define_attr_method property, value, false, &block - else - ActiveSupport::Deprecation.warn( - "Calling set_#{property} is deprecated. Please use `self.#{property} = 'the_name'` instead." - ) - - define_attr_method property, value, false - end - end - - def deprecated_original_property_getter(property) - ActiveSupport::Deprecation.warn("original_#{property} is deprecated. Define self.#{property} and call super instead.") - - if !instance_variable_defined?("@original_#{property}") && respond_to?("reset_#{property}") - send("reset_#{property}") - else - instance_variable_get("@original_#{property}") - end - end end end end diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index a2fe21043f..bf4f97b03b 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -209,7 +209,7 @@ module ActiveRecord # The following transaction covers any possible database side-effects of the # attributes assignment. For example, setting the IDs of a child collection. with_transaction_returning_status do - self.assign_attributes(attributes, options) + assign_attributes(attributes, options) save end end @@ -220,7 +220,7 @@ module ActiveRecord # The following transaction covers any possible database side-effects of the # attributes assignment. For example, setting the IDs of a child collection. with_transaction_returning_status do - self.assign_attributes(attributes, options) + assign_attributes(attributes, options) save! end end @@ -285,7 +285,7 @@ module ActiveRecord clear_association_cache IdentityMap.without do - fresh_object = self.class.unscoped { self.class.find(self.id, options) } + fresh_object = self.class.unscoped { self.class.find(id, options) } @attributes.update(fresh_object.instance_variable_get('@attributes')) end @@ -368,13 +368,5 @@ module ActiveRecord @new_record = false id end - - # Initializes the attributes array with keys matching the columns from the linked table and - # the values matching the corresponding default value of that column, so - # that a new instance, or one populated from a passed-in Hash, still has all the attributes - # that instances loaded from the database would. - def attributes_from_column_definition - self.class.column_defaults.dup - end end end diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index 199eee4359..de299dbe91 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -38,6 +38,7 @@ db_namespace = namespace :db do desc 'Create the database from config/database.yml for the current Rails.env (use db:create:all to create all dbs in the config)' task :create => :load_config do configs_for_environment.each { |config| create_database(config) } + ActiveRecord::Base.establish_connection(configs_for_environment.first) end def mysql_creation_options(config) diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index 0f57e9831d..bf9b4bf1c9 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -168,7 +168,7 @@ module ActiveRecord # This method is designed to perform select by a single column as direct SQL query # Returns <tt>Array</tt> with values of the specified column name - # The values has same data type as column. + # The values has same data type as column. # # Examples: # @@ -177,9 +177,8 @@ module ActiveRecord # Person.where(:confirmed => true).limit(5).pluck(:id) # def pluck(column_name) - scope = self.select(column_name) - self.connection.select_values(scope.to_sql).map! do |value| - type_cast_using_column(value, column_for(column_name)) + klass.connection.select_all(select(column_name).arel).map! do |attributes| + klass.type_cast_attribute(attributes.keys.first, klass.initialize_attributes(attributes)) end end diff --git a/activerecord/test/cases/attribute_methods/read_test.rb b/activerecord/test/cases/attribute_methods/read_test.rb index 86a240d93c..7665f1c12e 100644 --- a/activerecord/test/cases/attribute_methods/read_test.rb +++ b/activerecord/test/cases/attribute_methods/read_test.rb @@ -14,6 +14,7 @@ module ActiveRecord def setup @klass = Class.new do + def self.superclass; Base; end def self.base_class; self; end include ActiveRecord::AttributeMethods diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb index 5e9f8028e9..b6cf26f978 100644 --- a/activerecord/test/cases/attribute_methods_test.rb +++ b/activerecord/test/cases/attribute_methods_test.rb @@ -102,7 +102,6 @@ class AttributeMethodsTest < ActiveRecord::TestCase def test_respond_to? topic = Topic.find(1) assert_respond_to topic, "title" - assert_respond_to topic, "_title" assert_respond_to topic, "title?" assert_respond_to topic, "title=" assert_respond_to topic, :title @@ -114,19 +113,12 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert !topic.respond_to?(:nothingness) end - def test_deprecated_underscore_method - topic = Topic.find(1) - assert_equal topic.title, assert_deprecated { topic._title } - end - def test_respond_to_with_custom_primary_key keyboard = Keyboard.create assert_not_nil keyboard.key_number assert_equal keyboard.key_number, keyboard.id assert keyboard.respond_to?('key_number') - assert keyboard.respond_to?('_key_number') assert keyboard.respond_to?('id') - assert keyboard.respond_to?('_id') end # Syck calls respond_to? before actually calling initialize @@ -719,6 +711,26 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_equal nil, Topic.new.read_attribute(nil) end + # If B < A, and A defines an accessor for 'foo', we don't want to override + # that by defining a 'foo' method in the generated methods module for B. + # (That module will be inserted between the two, e.g. [B, <GeneratedAttributes>, A].) + def test_inherited_custom_accessors + klass = Class.new(ActiveRecord::Base) do + self.table_name = "topics" + self.abstract_class = true + def title; "omg"; end + def title=(val); self.author_name = val; end + end + subklass = Class.new(klass) + [klass, subklass].each(&:define_attribute_methods) + + topic = subklass.find(1) + assert_equal "omg", topic.title + + topic.title = "lol" + assert_equal "lol", topic.author_name + end + private def cached_columns @cached_columns ||= time_related_columns_on_topic.map(&:name) diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 2e2ab77f6e..6ff0c1355c 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1233,6 +1233,27 @@ class BasicsTest < ActiveRecord::TestCase assert_equal(myobj, topic.content) end + def test_serialized_attribute_in_base_class + Topic.serialize("content", Hash) + + hash = { 'content1' => 'value1', 'content2' => 'value2' } + important_topic = ImportantTopic.create("content" => hash) + assert_equal(hash, important_topic.content) + + important_topic.reload + assert_equal(hash, important_topic.content) + end + + def test_serialized_attribute_declared_in_subclass + hash = { 'important1' => 'value1', 'important2' => 'value2' } + important_topic = ImportantTopic.create("important" => hash) + assert_equal(hash, important_topic.important) + + important_topic.reload + assert_equal(hash, important_topic.important) + assert_equal(hash, important_topic.read_attribute(:important)) + end + def test_serialized_time_attribute myobj = Time.local(2008,1,1,1,0) topic = Topic.create("content" => myobj).reload @@ -1383,17 +1404,6 @@ class BasicsTest < ActiveRecord::TestCase assert_equal dev, dev.reload end - def test_set_table_name_with_value - k = Class.new( ActiveRecord::Base ) - k.table_name = "foo" - assert_equal "foo", k.table_name - - assert_deprecated do - k.set_table_name "bar" - end - assert_equal "bar", k.table_name - end - def test_switching_between_table_name assert_difference("GoodJoke.count") do Joke.table_name = "cold_jokes" @@ -1416,17 +1426,6 @@ class BasicsTest < ActiveRecord::TestCase assert_equal klass.connection.quote_table_name("bar"), klass.quoted_table_name end - def test_set_table_name_with_block - k = Class.new( ActiveRecord::Base ) - assert_deprecated do - k.set_table_name "foo" - k.set_table_name do - ActiveSupport::Deprecation.silence { original_table_name } + "ks" - end - end - assert_equal "fooks", k.table_name - end - def test_set_table_name_with_inheritance k = Class.new( ActiveRecord::Base ) def k.name; "Foo"; end @@ -1434,145 +1433,6 @@ class BasicsTest < ActiveRecord::TestCase assert_equal "foosks", k.table_name end - def test_original_table_name - k = Class.new(ActiveRecord::Base) - def k.name; "Foo"; end - k.table_name = "bar" - - assert_deprecated do - assert_equal "foos", k.original_table_name - end - - k = Class.new(ActiveRecord::Base) - k.table_name = "omg" - k.table_name = "wtf" - - assert_deprecated do - assert_equal "omg", k.original_table_name - end - end - - def test_set_primary_key_with_value - k = Class.new( ActiveRecord::Base ) - k.primary_key = "foo" - assert_equal "foo", k.primary_key - - assert_deprecated do - k.set_primary_key "bar" - end - assert_equal "bar", k.primary_key - end - - def test_set_primary_key_with_block - k = Class.new( ActiveRecord::Base ) - k.primary_key = 'id' - - assert_deprecated do - k.set_primary_key do - "sys_" + ActiveSupport::Deprecation.silence { original_primary_key } - end - end - assert_equal "sys_id", k.primary_key - end - - def test_original_primary_key - k = Class.new(ActiveRecord::Base) - def k.name; "Foo"; end - k.table_name = "posts" - k.primary_key = "bar" - - assert_deprecated do - assert_equal "id", k.original_primary_key - end - - k = Class.new(ActiveRecord::Base) - k.primary_key = "omg" - k.primary_key = "wtf" - - assert_deprecated do - assert_equal "omg", k.original_primary_key - end - end - - def test_set_inheritance_column_with_value - k = Class.new( ActiveRecord::Base ) - k.inheritance_column = "foo" - assert_equal "foo", k.inheritance_column - - assert_deprecated do - k.set_inheritance_column "bar" - end - assert_equal "bar", k.inheritance_column - end - - def test_set_inheritance_column_with_block - k = Class.new( ActiveRecord::Base ) - assert_deprecated do - k.set_inheritance_column do - ActiveSupport::Deprecation.silence { original_inheritance_column } + "_id" - end - end - assert_equal "type_id", k.inheritance_column - end - - def test_original_inheritance_column - k = Class.new(ActiveRecord::Base) - def k.name; "Foo"; end - k.inheritance_column = "omg" - - assert_deprecated do - assert_equal "type", k.original_inheritance_column - end - end - - def test_set_sequence_name_with_value - k = Class.new( ActiveRecord::Base ) - k.sequence_name = "foo" - assert_equal "foo", k.sequence_name - - assert_deprecated do - k.set_sequence_name "bar" - end - assert_equal "bar", k.sequence_name - end - - def test_set_sequence_name_with_block - k = Class.new( ActiveRecord::Base ) - k.table_name = "projects" - orig_name = k.sequence_name - return skip "sequences not supported by db" unless orig_name - - assert_deprecated do - k.set_sequence_name do - ActiveSupport::Deprecation.silence { original_sequence_name } + "_lol" - end - end - assert_equal orig_name + "_lol", k.sequence_name - end - - def test_original_sequence_name - k = Class.new(ActiveRecord::Base) - k.table_name = "projects" - orig_name = k.sequence_name - return skip "sequences not supported by db" unless orig_name - - k = Class.new(ActiveRecord::Base) - k.table_name = "projects" - k.sequence_name = "omg" - - assert_deprecated do - assert_equal orig_name, k.original_sequence_name - end - - k = Class.new(ActiveRecord::Base) - k.table_name = "projects" - k.sequence_name = "omg" - k.sequence_name = "wtf" - assert_deprecated do - assert_equal "omg", k.original_sequence_name - end - end - def test_sequence_name_with_abstract_class ak = Class.new(ActiveRecord::Base) ak.abstract_class = true @@ -1832,7 +1692,7 @@ class BasicsTest < ActiveRecord::TestCase def test_inspect_instance topic = topics(:first) - assert_equal %(#<Topic id: 1, title: "The First Topic", author_name: "David", author_email_address: "david@loudthinking.com", written_on: "#{topic.written_on.to_s(:db)}", bonus_time: "#{topic.bonus_time.to_s(:db)}", last_read: "#{topic.last_read.to_s(:db)}", content: "Have a nice day", approved: false, replies_count: 1, parent_id: nil, parent_title: nil, type: nil, group: nil, created_at: "#{topic.created_at.to_s(:db)}", updated_at: "#{topic.updated_at.to_s(:db)}">), topic.inspect + assert_equal %(#<Topic id: 1, title: "The First Topic", author_name: "David", author_email_address: "david@loudthinking.com", written_on: "#{topic.written_on.to_s(:db)}", bonus_time: "#{topic.bonus_time.to_s(:db)}", last_read: "#{topic.last_read.to_s(:db)}", content: "Have a nice day", important: nil, approved: false, replies_count: 1, parent_id: nil, parent_title: nil, type: nil, group: nil, created_at: "#{topic.created_at.to_s(:db)}", updated_at: "#{topic.updated_at.to_s(:db)}">), topic.inspect end def test_inspect_new_instance diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index 5abf3d1af4..66c801ca75 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -458,7 +458,6 @@ class CalculationsTest < ActiveRecord::TestCase assert_equal [ topic.approved ], relation.pluck(:approved) assert_equal [ topic.last_read ], relation.pluck(:last_read) assert_equal [ topic.written_on ], relation.pluck(:written_on) - end def test_pluck_and_uniq @@ -471,4 +470,12 @@ class CalculationsTest < ActiveRecord::TestCase assert_equal [contract.id], company.contracts.pluck(:id) end + def test_pluck_with_serialization + t = Topic.create!(:content => { :foo => :bar }) + assert_equal [{:foo => :bar}], Topic.where(:id => t.id).pluck(:content) + end + + def test_pluck_with_qualified_column_name + assert_equal [1,2,3,4], Topic.order(:id).pluck("topics.id") + end end diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb index 5978b244d4..f7ee83998d 100644 --- a/activerecord/test/cases/locking_test.rb +++ b/activerecord/test/cases/locking_test.rb @@ -226,48 +226,6 @@ class OptimisticLockingTest < ActiveRecord::TestCase end end -class SetLockingColumnTest < ActiveRecord::TestCase - def test_set_set_locking_column_with_value - k = Class.new( ActiveRecord::Base ) - k.locking_column = "foo" - assert_equal "foo", k.locking_column - - assert_deprecated do - k.set_locking_column "bar" - end - assert_equal "bar", k.locking_column - end - - def test_set_locking_column_with_block - k = Class.new( ActiveRecord::Base ) - k.locking_column = 'foo' - - assert_deprecated do - k.set_locking_column do - "lock_" + ActiveSupport::Deprecation.silence { original_locking_column } - end - end - assert_equal "lock_foo", k.locking_column - end - - def test_original_locking_column - k = Class.new(ActiveRecord::Base) - k.locking_column = "bar" - - assert_deprecated do - assert_equal ActiveRecord::Locking::Optimistic::ClassMethods::DEFAULT_LOCKING_COLUMN, k.original_locking_column - end - - k = Class.new(ActiveRecord::Base) - k.locking_column = "omg" - k.locking_column = "wtf" - - assert_deprecated do - assert_equal "omg", k.original_locking_column - end - end -end - class OptimisticLockingWithSchemaChangeTest < ActiveRecord::TestCase fixtures :people, :legacy_things, :references diff --git a/activerecord/test/cases/mass_assignment_security_test.rb b/activerecord/test/cases/mass_assignment_security_test.rb index 9fff50edcb..8122857f52 100644 --- a/activerecord/test/cases/mass_assignment_security_test.rb +++ b/activerecord/test/cases/mass_assignment_security_test.rb @@ -50,6 +50,13 @@ module MassAssignmentTestHelpers assert_equal 'm', person.gender assert_equal 'rides a sweet bike', person.comments end + + def with_strict_sanitizer + ActiveRecord::Base.mass_assignment_sanitizer = :strict + yield + ensure + ActiveRecord::Base.mass_assignment_sanitizer = :logger + end end module MassAssignmentRelationTestHelpers @@ -323,6 +330,13 @@ class MassAssignmentSecurityHasOneRelationsTest < ActiveRecord::TestCase assert_all_attributes(best_friend) end + def test_has_one_build_with_strict_sanitizer + with_strict_sanitizer do + best_friend = @person.build_best_friend(attributes_hash.except(:id, :comments)) + assert_equal @person.id, best_friend.best_friend_id + end + end + # create def test_has_one_create_with_attr_protected_attributes @@ -350,6 +364,13 @@ class MassAssignmentSecurityHasOneRelationsTest < ActiveRecord::TestCase assert_all_attributes(best_friend) end + def test_has_one_create_with_strict_sanitizer + with_strict_sanitizer do + best_friend = @person.create_best_friend(attributes_hash.except(:id, :comments)) + assert_equal @person.id, best_friend.best_friend_id + end + end + # create! def test_has_one_create_with_bang_with_attr_protected_attributes @@ -377,6 +398,13 @@ class MassAssignmentSecurityHasOneRelationsTest < ActiveRecord::TestCase assert_all_attributes(best_friend) end + def test_has_one_create_with_bang_with_strict_sanitizer + with_strict_sanitizer do + best_friend = @person.create_best_friend!(attributes_hash.except(:id, :comments)) + assert_equal @person.id, best_friend.best_friend_id + end + end + end @@ -438,6 +466,13 @@ class MassAssignmentSecurityBelongsToRelationsTest < ActiveRecord::TestCase assert_all_attributes(best_friend) end + def test_belongs_to_create_with_strict_sanitizer + with_strict_sanitizer do + best_friend = @person.create_best_friend_of(attributes_hash.except(:id, :comments)) + assert_equal best_friend.id, @person.best_friend_of_id + end + end + # create! def test_belongs_to_create_with_bang_with_attr_protected_attributes @@ -465,6 +500,13 @@ class MassAssignmentSecurityBelongsToRelationsTest < ActiveRecord::TestCase assert_all_attributes(best_friend) end + def test_belongs_to_create_with_bang_with_strict_sanitizer + with_strict_sanitizer do + best_friend = @person.create_best_friend_of!(attributes_hash.except(:id, :comments)) + assert_equal best_friend.id, @person.best_friend_of_id + end + end + end @@ -499,6 +541,13 @@ class MassAssignmentSecurityHasManyRelationsTest < ActiveRecord::TestCase assert_all_attributes(best_friend) end + def test_has_many_build_with_strict_sanitizer + with_strict_sanitizer do + best_friend = @person.best_friends.build(attributes_hash.except(:id, :comments)) + assert_equal @person.id, best_friend.best_friend_id + end + end + # create def test_has_many_create_with_attr_protected_attributes @@ -526,6 +575,13 @@ class MassAssignmentSecurityHasManyRelationsTest < ActiveRecord::TestCase assert_all_attributes(best_friend) end + def test_has_many_create_with_strict_sanitizer + with_strict_sanitizer do + best_friend = @person.best_friends.create(attributes_hash.except(:id, :comments)) + assert_equal @person.id, best_friend.best_friend_id + end + end + # create! def test_has_many_create_with_bang_with_attr_protected_attributes @@ -553,6 +609,13 @@ class MassAssignmentSecurityHasManyRelationsTest < ActiveRecord::TestCase assert_all_attributes(best_friend) end + def test_has_many_create_with_bang_with_strict_sanitizer + with_strict_sanitizer do + best_friend = @person.best_friends.create!(attributes_hash.except(:id, :comments)) + assert_equal @person.id, best_friend.best_friend_id + end + end + end diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb index 2f28dd4767..2ae9cb4888 100644 --- a/activerecord/test/cases/nested_attributes_test.rb +++ b/activerecord/test/cases/nested_attributes_test.rb @@ -617,11 +617,6 @@ module NestedAttributesOnACollectionAssociationTests assert_equal ['Grace OMalley', 'Privateers Greed'], [@child_1.name, @child_2.name] end - def test_should_take_a_hash_with_owner_attributes_and_assign_the_attributes_to_the_associated_model - @pirate.birds.create :name => 'bird', :pirate_attributes => {:id => @pirate.id.to_s, :catchphrase => 'Holla!'} - assert_equal 'Holla!', @pirate.reload.catchphrase - end - def test_should_raise_RecordNotFound_if_an_id_is_given_but_doesnt_return_a_record assert_raise_with_message ActiveRecord::RecordNotFound, "Couldn't find #{@child_1.class.name} with ID=1234567890 for Pirate with ID=#{@pirate.id}" do @pirate.attributes = { association_getter => [{ :id => 1234567890 }] } diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb index b30db542a7..7fd15027eb 100644 --- a/activerecord/test/cases/reflection_test.rb +++ b/activerecord/test/cases/reflection_test.rb @@ -36,25 +36,25 @@ class ReflectionTest < ActiveRecord::TestCase def test_read_attribute_names assert_equal( - %w( id title author_name author_email_address bonus_time written_on last_read content group approved replies_count parent_id parent_title type created_at updated_at ).sort, + %w( id title author_name author_email_address bonus_time written_on last_read content important group approved replies_count parent_id parent_title type created_at updated_at ).sort, @first.attribute_names.sort ) end def test_columns - assert_equal 16, Topic.columns.length + assert_equal 17, Topic.columns.length end def test_columns_are_returned_in_the_order_they_were_declared column_names = Topic.columns.map { |column| column.name } - assert_equal %w(id title author_name author_email_address written_on bonus_time last_read content approved replies_count parent_id parent_title type group created_at updated_at), column_names + assert_equal %w(id title author_name author_email_address written_on bonus_time last_read content important approved replies_count parent_id parent_title type group created_at updated_at), column_names end def test_content_columns content_columns = Topic.content_columns content_column_names = content_columns.map {|column| column.name} - assert_equal 12, content_columns.length - assert_equal %w(title author_name author_email_address written_on bonus_time last_read content group approved parent_title created_at updated_at).sort, content_column_names.sort + assert_equal 13, content_columns.length + assert_equal %w(title author_name author_email_address written_on bonus_time last_read content important group approved parent_title created_at updated_at).sort, content_column_names.sort end def test_column_string_type_and_limit diff --git a/activerecord/test/models/person.rb b/activerecord/test/models/person.rb index 967a3625aa..36eb08d02f 100644 --- a/activerecord/test/models/person.rb +++ b/activerecord/test/models/person.rb @@ -54,7 +54,7 @@ class LoosePerson < ActiveRecord::Base self.table_name = 'people' self.abstract_class = true - attr_protected :comments + attr_protected :comments, :best_friend_id, :best_friend_of_id attr_protected :as => :admin has_one :best_friend, :class_name => 'LoosePerson', :foreign_key => :best_friend_id @@ -81,4 +81,4 @@ class TightPerson < ActiveRecord::Base accepts_nested_attributes_for :best_friend, :best_friend_of, :best_friends end -class TightDescendant < TightPerson; end
\ No newline at end of file +class TightDescendant < TightPerson; end diff --git a/activerecord/test/models/topic.rb b/activerecord/test/models/topic.rb index ede662450e..1a1a18166a 100644 --- a/activerecord/test/models/topic.rb +++ b/activerecord/test/models/topic.rb @@ -108,6 +108,10 @@ class Topic < ActiveRecord::Base def after_create_for_transaction; end end +class ImportantTopic < Topic + serialize :important, Hash +end + module Web class Topic < ActiveRecord::Base has_many :replies, :dependent => :destroy, :foreign_key => "parent_id", :class_name => 'Web::Reply' diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index bb08f5c181..5933e1f46e 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -607,8 +607,10 @@ ActiveRecord::Schema.define do # Oracle SELECT WHERE clause which causes many unit test failures if current_adapter?(:OracleAdapter) t.string :content, :limit => 4000 + t.string :important, :limit => 4000 else t.text :content + t.text :important end t.boolean :approved, :default => true t.integer :replies_count, :default => 0 diff --git a/activerecord/test/support/connection.rb b/activerecord/test/support/connection.rb index a39794fa39..56369da346 100644 --- a/activerecord/test/support/connection.rb +++ b/activerecord/test/support/connection.rb @@ -1,4 +1,4 @@ -require 'logger' +require 'active_support/logger' require_dependency 'models/course' module ARTest @@ -12,7 +12,7 @@ module ARTest def self.connect puts "Using #{connection_name} with Identity Map #{ActiveRecord::IdentityMap.enabled? ? 'on' : 'off'}" - ActiveRecord::Base.logger = Logger.new("debug.log") + ActiveRecord::Base.logger = ActiveSupport::Logger.new("debug.log") ActiveRecord::Base.configurations = connection_config ActiveRecord::Base.establish_connection 'arunit' Course.establish_connection 'arunit2' |