From a68a3e9af6a02c9ce18d3eec87558241095ce8fb Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Thu, 21 Jan 2010 21:15:01 +0530 Subject: Simplify finder method definitions --- .../lib/active_record/relation/query_methods.rb | 24 ++++++++++------------ 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index ce3e4e8eed..8954f2d12b 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -8,11 +8,10 @@ module ActiveRecord class_eval <<-CEVAL def #{query_method}(*args) - spawn.tap do |new_relation| - new_relation.#{query_method}_values ||= [] - value = Array.wrap(args.flatten).reject {|x| x.blank? } - new_relation.#{query_method}_values += value if value.present? - end + new_relation = spawn + value = Array.wrap(args.flatten).reject {|x| x.blank? } + new_relation.#{query_method}_values += value if value.present? + new_relation end CEVAL end @@ -20,11 +19,10 @@ module ActiveRecord [:where, :having].each do |query_method| class_eval <<-CEVAL def #{query_method}(*args) - spawn.tap do |new_relation| - new_relation.#{query_method}_values ||= [] - value = build_where(*args) - new_relation.#{query_method}_values += [*value] if value.present? - end + new_relation = spawn + value = build_where(*args) + new_relation.#{query_method}_values += [*value] if value.present? + new_relation end CEVAL end @@ -34,9 +32,9 @@ module ActiveRecord class_eval <<-CEVAL def #{query_method}(value = true) - spawn.tap do |new_relation| - new_relation.#{query_method}_value = value - end + new_relation = spawn + new_relation.#{query_method}_value = value + new_relation end CEVAL end -- cgit v1.2.3 From 6d30002a52133bd105adb29084f4cc72b1ee847f Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Fri, 22 Jan 2010 00:51:45 +0530 Subject: Revert "Refactoring attributes/types" [#3348 state:open] This reverts commit f936a1f100e75082081e782e5cceb272885c2df7. Conflicts: activerecord/lib/active_record.rb activerecord/lib/active_record/base.rb Revert "Fixed: #without_typecast should only disable typecasting on the duplicated attributes" [#3387 state:open] This reverts commit 2831996483c6a045f1f38d8030256eb58d9771c3. Reason : It's not generating attribute methods properly, making object.column 5x slower. --- .../attribute_methods/before_type_cast.rb | 13 ++- .../lib/active_record/attribute_methods/query.rb | 20 +++- .../lib/active_record/attribute_methods/read.rb | 49 ++++++++- .../attribute_methods/time_zone_conversion.rb | 48 +++++++-- .../lib/active_record/attribute_methods/write.rb | 9 +- activerecord/lib/active_record/attributes.rb | 37 ------- .../lib/active_record/attributes/aliasing.rb | 42 -------- activerecord/lib/active_record/attributes/store.rb | 15 --- .../lib/active_record/attributes/typecasting.rb | 117 --------------------- activerecord/lib/active_record/base.rb | 37 +++++-- activerecord/lib/active_record/types.rb | 38 ------- activerecord/lib/active_record/types/number.rb | 30 ------ activerecord/lib/active_record/types/object.rb | 37 ------- activerecord/lib/active_record/types/serialize.rb | 33 ------ .../lib/active_record/types/time_with_zone.rb | 20 ---- activerecord/lib/active_record/types/unknown.rb | 37 ------- 16 files changed, 148 insertions(+), 434 deletions(-) delete mode 100644 activerecord/lib/active_record/attributes.rb delete mode 100644 activerecord/lib/active_record/attributes/aliasing.rb delete mode 100644 activerecord/lib/active_record/attributes/store.rb delete mode 100644 activerecord/lib/active_record/attributes/typecasting.rb delete mode 100644 activerecord/lib/active_record/types.rb delete mode 100644 activerecord/lib/active_record/types/number.rb delete mode 100644 activerecord/lib/active_record/types/object.rb delete mode 100644 activerecord/lib/active_record/types/serialize.rb delete mode 100644 activerecord/lib/active_record/types/time_with_zone.rb delete mode 100644 activerecord/lib/active_record/types/unknown.rb (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/attribute_methods/before_type_cast.rb b/activerecord/lib/active_record/attribute_methods/before_type_cast.rb index 74921241f7..a4e144f233 100644 --- a/activerecord/lib/active_record/attribute_methods/before_type_cast.rb +++ b/activerecord/lib/active_record/attribute_methods/before_type_cast.rb @@ -8,18 +8,25 @@ module ActiveRecord end def read_attribute_before_type_cast(attr_name) - _attributes.without_typecast[attr_name] + @attributes[attr_name] end # Returns a hash of attributes before typecasting and deserialization. def attributes_before_type_cast - _attributes.without_typecast + self.attribute_names.inject({}) do |attrs, name| + attrs[name] = read_attribute_before_type_cast(name) + attrs + end end private # Handle *_before_type_cast for method_missing. def attribute_before_type_cast(attribute_name) - read_attribute_before_type_cast(attribute_name) + if attribute_name == 'id' + read_attribute_before_type_cast(self.class.primary_key) + else + read_attribute_before_type_cast(attribute_name) + end end end end diff --git a/activerecord/lib/active_record/attribute_methods/query.rb b/activerecord/lib/active_record/attribute_methods/query.rb index 0154ee35f8..a949d80120 100644 --- a/activerecord/lib/active_record/attribute_methods/query.rb +++ b/activerecord/lib/active_record/attribute_methods/query.rb @@ -8,7 +8,23 @@ module ActiveRecord end def query_attribute(attr_name) - _attributes.has?(attr_name) + unless value = read_attribute(attr_name) + false + else + column = self.class.columns_hash[attr_name] + if column.nil? + if Numeric === value || value !~ /[^0-9]/ + !value.to_i.zero? + else + return false if ActiveRecord::ConnectionAdapters::Column::FALSE_VALUES.include?(value) + !value.blank? + end + elsif column.number? + !value.zero? + else + !value.blank? + end + end end private @@ -19,5 +35,3 @@ module ActiveRecord end end end - - diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb index 97caec7744..3da3d9d8cc 100644 --- a/activerecord/lib/active_record/attribute_methods/read.rb +++ b/activerecord/lib/active_record/attribute_methods/read.rb @@ -37,7 +37,11 @@ module ActiveRecord protected def define_method_attribute(attr_name) - define_read_method(attr_name.to_sym, attr_name, columns_hash[attr_name]) + if self.serialized_attributes[attr_name] + define_read_method_for_serialized_attribute(attr_name) + else + define_read_method(attr_name.to_sym, attr_name, columns_hash[attr_name]) + end if attr_name == primary_key && attr_name != "id" define_read_method(:id, attr_name, columns_hash[attr_name]) @@ -45,12 +49,18 @@ module ActiveRecord end private + # Define read method for serialized attribute. + def define_read_method_for_serialized_attribute(attr_name) + generated_attribute_methods.module_eval("def #{attr_name}; unserialize_attribute('#{attr_name}'); end", __FILE__, __LINE__) + end # Define an attribute reader method. Cope with nil column. def define_read_method(symbol, attr_name, column) - access_code = "_attributes['#{attr_name}']" + cast_code = column.type_cast_code('v') if column + access_code = cast_code ? "(v=@attributes['#{attr_name}']) && #{cast_code}" : "@attributes['#{attr_name}']" + unless attr_name.to_s == self.primary_key.to_s - access_code = access_code.insert(0, "missing_attribute('#{attr_name}', caller) unless _attributes.key?('#{attr_name}'); ") + access_code = access_code.insert(0, "missing_attribute('#{attr_name}', caller) unless @attributes.has_key?('#{attr_name}'); ") end if cache_attribute?(attr_name) @@ -63,7 +73,38 @@ module ActiveRecord # Returns the value of the attribute identified by attr_name 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) - _attributes[attr_name] + attr_name = attr_name.to_s + attr_name = self.class.primary_key if attr_name == 'id' + if !(value = @attributes[attr_name]).nil? + if column = column_for_attribute(attr_name) + if unserializable_attribute?(attr_name, column) + unserialize_attribute(attr_name) + else + column.type_cast(value) + end + else + value + end + else + nil + end + end + + # Returns true if the attribute is of a text column and marked for serialization. + def unserializable_attribute?(attr_name, column) + column.text? && self.class.serialized_attributes[attr_name] + end + + # Returns the unserialized object of the attribute. + def unserialize_attribute(attr_name) + unserialized_object = object_from_yaml(@attributes[attr_name]) + + if unserialized_object.is_a?(self.class.serialized_attributes[attr_name]) || unserialized_object.nil? + @attributes.frozen? ? unserialized_object : @attributes[attr_name] = unserialized_object + else + raise SerializationTypeMismatch, + "#{attr_name} was supposed to be a #{self.class.serialized_attributes[attr_name]}, but was a #{unserialized_object.class.to_s}" + end end private diff --git a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb index 4ac0c7f608..a8e3e28a7a 100644 --- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb +++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb @@ -12,20 +12,48 @@ module ActiveRecord end module ClassMethods - - def cache_attribute?(attr_name) - time_zone_aware?(attr_name) || super - end - protected + # Defined for all +datetime+ and +timestamp+ attributes when +time_zone_aware_attributes+ are enabled. + # This enhanced read method automatically converts the UTC time stored in the database to the time zone stored in Time.zone. + def define_method_attribute(attr_name) + if create_time_zone_conversion_attribute?(attr_name, columns_hash[attr_name]) + method_body = <<-EOV + def #{attr_name}(reload = false) + cached = @attributes_cache['#{attr_name}'] + return cached if cached && !reload + time = read_attribute('#{attr_name}') + @attributes_cache['#{attr_name}'] = time.acts_like?(:time) ? time.in_time_zone : time + end + EOV + generated_attribute_methods.module_eval(method_body, __FILE__, __LINE__) + else + super + end + end - def time_zone_aware?(attr_name) - column = columns_hash[attr_name] - time_zone_aware_attributes && - !skip_time_zone_conversion_for_attributes.include?(attr_name.to_sym) && - [:datetime, :timestamp].include?(column.type) + # Defined for all +datetime+ and +timestamp+ attributes when +time_zone_aware_attributes+ are enabled. + # This enhanced write method will automatically convert the time passed to it to the zone stored in Time.zone. + def define_method_attribute=(attr_name) + if create_time_zone_conversion_attribute?(attr_name, columns_hash[attr_name]) + method_body = <<-EOV + def #{attr_name}=(time) + unless time.acts_like?(:time) + time = time.is_a?(String) ? Time.zone.parse(time) : time.to_time rescue time + end + time = time.in_time_zone rescue nil if time + write_attribute(:#{attr_name}, time) + end + EOV + generated_attribute_methods.module_eval(method_body, __FILE__, __LINE__) + else + super + end end + private + def create_time_zone_conversion_attribute?(name, column) + time_zone_aware_attributes && !skip_time_zone_conversion_for_attributes.include?(name.to_sym) && [:datetime, :timestamp].include?(column.type) + end end end end diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb index 37eadbe0a9..e31acac050 100644 --- a/activerecord/lib/active_record/attribute_methods/write.rb +++ b/activerecord/lib/active_record/attribute_methods/write.rb @@ -17,9 +17,14 @@ module ActiveRecord # Updates the attribute identified by attr_name with the specified +value+. Empty strings for fixnum and float # columns are turned into +nil+. def write_attribute(attr_name, value) - attr_name = _attributes.unalias(attr_name) + attr_name = attr_name.to_s + attr_name = self.class.primary_key if attr_name == 'id' @attributes_cache.delete(attr_name) - _attributes[attr_name] = value + if (column = column_for_attribute(attr_name)) && column.number? + @attributes[attr_name] = convert_number_column_value(value) + else + @attributes[attr_name] = value + end end private diff --git a/activerecord/lib/active_record/attributes.rb b/activerecord/lib/active_record/attributes.rb deleted file mode 100644 index e4d9e89821..0000000000 --- a/activerecord/lib/active_record/attributes.rb +++ /dev/null @@ -1,37 +0,0 @@ -module ActiveRecord - module Attributes - - # Returns true if the given attribute is in the attributes hash - def has_attribute?(attr_name) - _attributes.key?(attr_name) - end - - # Returns an array of names for the attributes available on this object sorted alphabetically. - def attribute_names - _attributes.keys.sort! - end - - # Returns a hash of all the attributes with their names as keys and the values of the attributes as values. - def attributes - attributes = _attributes.dup - attributes.typecast! unless _attributes.frozen? - attributes.to_h - end - - protected - - # Not to be confused with the public #attributes method, which returns a typecasted Hash. - def _attributes - @attributes - end - - def initialize_attribute_store(merge_attributes = nil) - @attributes = ActiveRecord::Attributes::Store.new - @attributes.merge!(merge_attributes) if merge_attributes - @attributes.types.merge!(self.class.attribute_types) - @attributes.aliases.merge!('id' => self.class.primary_key) unless 'id' == self.class.primary_key - @attributes - end - - end -end diff --git a/activerecord/lib/active_record/attributes/aliasing.rb b/activerecord/lib/active_record/attributes/aliasing.rb deleted file mode 100644 index db77739d1f..0000000000 --- a/activerecord/lib/active_record/attributes/aliasing.rb +++ /dev/null @@ -1,42 +0,0 @@ -module ActiveRecord - module Attributes - module Aliasing - # Allows access to keys using aliased names. - # - # Example: - # class Attributes < Hash - # include Aliasing - # end - # - # attributes = Attributes.new - # attributes.aliases['id'] = 'fancy_primary_key' - # attributes['fancy_primary_key'] = 2020 - # - # attributes['id'] - # => 2020 - # - # Additionally, symbols are always aliases of strings: - # attributes[:fancy_primary_key] - # => 2020 - # - def [](key) - super(unalias(key)) - end - - def []=(key, value) - super(unalias(key), value) - end - - def aliases - @aliases ||= {} - end - - def unalias(key) - key = key.to_s - aliases[key] || key - end - - end - end -end - diff --git a/activerecord/lib/active_record/attributes/store.rb b/activerecord/lib/active_record/attributes/store.rb deleted file mode 100644 index 61109f4acc..0000000000 --- a/activerecord/lib/active_record/attributes/store.rb +++ /dev/null @@ -1,15 +0,0 @@ -module ActiveRecord - module Attributes - class Store < Hash - include ActiveRecord::Attributes::Typecasting - include ActiveRecord::Attributes::Aliasing - - # Attributes not mapped to a column are handled using Type::Unknown, - # which enables boolean typecasting for unmapped keys. - def types - @types ||= Hash.new(Type::Unknown.new) - end - - end - end -end diff --git a/activerecord/lib/active_record/attributes/typecasting.rb b/activerecord/lib/active_record/attributes/typecasting.rb deleted file mode 100644 index 56c32f9895..0000000000 --- a/activerecord/lib/active_record/attributes/typecasting.rb +++ /dev/null @@ -1,117 +0,0 @@ -module ActiveRecord - module Attributes - module Typecasting - # Typecasts values during access based on their key mapping to a Type. - # - # Example: - # class Attributes < Hash - # include Typecasting - # end - # - # attributes = Attributes.new - # attributes.types['comments_count'] = Type::Integer - # attributes['comments_count'] = '5' - # - # attributes['comments_count'] - # => 5 - # - # To support keys not mapped to a typecaster, add a default to types. - # attributes.types.default = Type::Unknown - # attributes['age'] = '25' - # attributes['age'] - # => '25' - # - # A valid type supports #cast, #precast, #boolean, and #appendable? methods. - # - def [](key) - value = super(key) - typecast_read(key, value) - end - - def []=(key, value) - super(key, typecast_write(key, value)) - end - - def to_h - hash = {} - hash.merge!(self) - hash - end - - def dup # :nodoc: - copy = super - copy.types = types.dup - copy - end - - # Provides a duplicate with typecasting disabled. - # - # Example: - # attributes = Attributes.new - # attributes.types['comments_count'] = Type::Integer - # attributes['comments_count'] = '5' - # - # attributes.without_typecast['comments_count'] - # => '5' - # - def without_typecast - dup.without_typecast! - end - - def without_typecast! - types.clear - self - end - - def typecast! - keys.each { |key| self[key] = self[key] } - self - end - - # Check if key has a value that typecasts to true. - # - # attributes = Attributes.new - # attributes.types['comments_count'] = Type::Integer - # - # attributes['comments_count'] = 0 - # attributes.has?('comments_count') - # => false - # - # attributes['comments_count'] = 1 - # attributes.has?('comments_count') - # => true - # - def has?(key) - value = self[key] - boolean_typecast(key, value) - end - - def types - @types ||= {} - end - - protected - - def types=(other_types) - @types = other_types - end - - def boolean_typecast(key, value) - value ? types[key].boolean(value) : false - end - - def typecast_read(key, value) - type = types[key] - value = type.cast(value) - self[key] = value if type.appendable? && !frozen? - - value - end - - def typecast_write(key, value) - types[key].precast(value) - end - - end - end -end diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index bc1b0bde31..f1b2b3b979 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1200,7 +1200,7 @@ module ActiveRecord #:nodoc: def instantiate(record) object = find_sti_class(record[inheritance_column]).allocate - object.send(:initialize_attribute_store, record) + object.instance_variable_set(:'@attributes', record) object.instance_variable_set(:'@attributes_cache', {}) object.send(:_run_find_callbacks) @@ -1663,7 +1663,7 @@ module ActiveRecord #:nodoc: # In both instances, valid attribute keys are determined by the column names of the associated table -- # hence you can't have attributes that aren't part of the table columns. def initialize(attributes = nil) - initialize_attribute_store(attributes_from_column_definition) + @attributes = attributes_from_column_definition @attributes_cache = {} @new_record = true ensure_proper_type @@ -1694,7 +1694,7 @@ module ActiveRecord #:nodoc: callback(:after_initialize) if respond_to_without_attributes?(:after_initialize) cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast) cloned_attributes.delete(self.class.primary_key) - initialize_attribute_store(cloned_attributes) + @attributes = cloned_attributes clear_aggregation_cache @attributes_cache = {} @new_record = true @@ -1924,11 +1924,21 @@ module ActiveRecord #:nodoc: def reload(options = nil) clear_aggregation_cache clear_association_cache - _attributes.update(self.class.find(self.id, options).instance_variable_get('@attributes')) + @attributes.update(self.class.find(self.id, options).instance_variable_get('@attributes')) @attributes_cache = {} self end + # Returns true if the given attribute is in the attributes hash + def has_attribute?(attr_name) + @attributes.has_key?(attr_name.to_s) + end + + # Returns an array of names for the attributes available on this object sorted alphabetically. + def attribute_names + @attributes.keys.sort + end + # Returns the value of the attribute identified by attr_name 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)). # (Alias for the protected read_attribute method). @@ -2262,7 +2272,7 @@ module ActiveRecord #:nodoc: end def instantiate_time_object(name, values) - if self.class.send(:time_zone_aware?, name) + if self.class.send(:create_time_zone_conversion_attribute?, name, column_for_attribute(name)) Time.zone.local(*values) else Time.time_with_datetime_fallback(@@default_timezone, *values) @@ -2345,6 +2355,22 @@ module ActiveRecord #:nodoc: comma_pair_list(quote_columns(quoter, hash)) end + def convert_number_column_value(value) + if value == false + 0 + elsif value == true + 1 + elsif value.is_a?(String) && value.blank? + nil + else + value + end + end + + def object_from_yaml(string) + return string unless string.is_a?(String) && string =~ /^---/ + YAML::load(string) rescue string + end end Base.class_eval do @@ -2359,7 +2385,6 @@ module ActiveRecord #:nodoc: include AttributeMethods::PrimaryKey include AttributeMethods::TimeZoneConversion include AttributeMethods::Dirty - include Attributes, Types include Callbacks, ActiveModel::Observing, Timestamp include Associations, AssociationPreload, NamedScope include ActiveModel::Conversion diff --git a/activerecord/lib/active_record/types.rb b/activerecord/lib/active_record/types.rb deleted file mode 100644 index 74f569352b..0000000000 --- a/activerecord/lib/active_record/types.rb +++ /dev/null @@ -1,38 +0,0 @@ -module ActiveRecord - module Types - extend ActiveSupport::Concern - - module ClassMethods - - def attribute_types - attribute_types = {} - columns.each do |column| - options = {} - options[:time_zone_aware] = time_zone_aware?(column.name) - options[:serialize] = serialized_attributes[column.name] - - attribute_types[column.name] = to_type(column, options) - end - attribute_types - end - - private - - def to_type(column, options = {}) - type_class = if options[:time_zone_aware] - Type::TimeWithZone - elsif options[:serialize] - Type::Serialize - elsif [ :integer, :float, :decimal ].include?(column.type) - Type::Number - else - Type::Object - end - - type_class.new(column, options) - end - - end - - end -end diff --git a/activerecord/lib/active_record/types/number.rb b/activerecord/lib/active_record/types/number.rb deleted file mode 100644 index cfbe877575..0000000000 --- a/activerecord/lib/active_record/types/number.rb +++ /dev/null @@ -1,30 +0,0 @@ -module ActiveRecord - module Type - class Number < Object - - def boolean(value) - value = cast(value) - !(value.nil? || value.zero?) - end - - def precast(value) - convert_number_column_value(value) - end - - private - - def convert_number_column_value(value) - if value == false - 0 - elsif value == true - 1 - elsif value.is_a?(String) && value.blank? - nil - else - value - end - end - - end - end -end \ No newline at end of file diff --git a/activerecord/lib/active_record/types/object.rb b/activerecord/lib/active_record/types/object.rb deleted file mode 100644 index ec3f861abd..0000000000 --- a/activerecord/lib/active_record/types/object.rb +++ /dev/null @@ -1,37 +0,0 @@ -module ActiveRecord - module Type - module Casting - - def cast(value) - typecaster.type_cast(value) - end - - def precast(value) - value - end - - def boolean(value) - cast(value).present? - end - - # Attributes::Typecasting stores appendable? types (e.g. serialized Arrays) when typecasting reads. - def appendable? - false - end - - end - - class Object - include Casting - - attr_reader :name, :options - attr_reader :typecaster - - def initialize(typecaster = nil, options = {}) - @typecaster, @options = typecaster, options - end - - end - - end -end \ No newline at end of file diff --git a/activerecord/lib/active_record/types/serialize.rb b/activerecord/lib/active_record/types/serialize.rb deleted file mode 100644 index 7b6af1981f..0000000000 --- a/activerecord/lib/active_record/types/serialize.rb +++ /dev/null @@ -1,33 +0,0 @@ -module ActiveRecord - module Type - class Serialize < Object - - def cast(value) - unserialize(value) - end - - def appendable? - true - end - - protected - - def unserialize(value) - unserialized_object = object_from_yaml(value) - - if unserialized_object.is_a?(@options[:serialize]) || unserialized_object.nil? - unserialized_object - else - raise SerializationTypeMismatch, - "#{name} was supposed to be a #{@options[:serialize]}, but was a #{unserialized_object.class.to_s}" - end - end - - def object_from_yaml(string) - return string unless string.is_a?(String) && string =~ /^---/ - YAML::load(string) rescue string - end - - end - end -end \ No newline at end of file diff --git a/activerecord/lib/active_record/types/time_with_zone.rb b/activerecord/lib/active_record/types/time_with_zone.rb deleted file mode 100644 index 3a8b9292f9..0000000000 --- a/activerecord/lib/active_record/types/time_with_zone.rb +++ /dev/null @@ -1,20 +0,0 @@ -module ActiveRecord - module Type - class TimeWithZone < Object - - def cast(time) - time = super(time) - time.acts_like?(:time) ? time.in_time_zone : time - end - - def precast(time) - unless time.acts_like?(:time) - time = time.is_a?(String) ? ::Time.zone.parse(time) : time.to_time rescue time - end - time = time.in_time_zone rescue nil if time - super(time) - end - - end - end -end diff --git a/activerecord/lib/active_record/types/unknown.rb b/activerecord/lib/active_record/types/unknown.rb deleted file mode 100644 index f832c7b304..0000000000 --- a/activerecord/lib/active_record/types/unknown.rb +++ /dev/null @@ -1,37 +0,0 @@ -module ActiveRecord - module Type - # Useful for handling attributes not mapped to types. Performs some boolean typecasting, - # but otherwise leaves the value untouched. - class Unknown - - def cast(value) - value - end - - def precast(value) - value - end - - # Attempts typecasting to handle numeric, false and blank values. - def boolean(value) - empty = (numeric?(value) && value.to_i.zero?) || false?(value) || value.blank? - !empty - end - - def appendable? - false - end - - protected - - def false?(value) - ActiveRecord::ConnectionAdapters::Column::FALSE_VALUES.include?(value) - end - - def numeric?(value) - Numeric === value || value !~ /[^0-9]/ - end - - end - end -end \ No newline at end of file -- cgit v1.2.3 From ee8c006dac7d76f79fb43df97a4ab8a2ae87b8b2 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Fri, 22 Jan 2010 20:10:29 +0530 Subject: Allow calling class methods on a Relation --- activerecord/lib/active_record/relation.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 04b85119cb..fa99e3f891 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -301,6 +301,8 @@ module ActiveRecord def method_missing(method, *args, &block) if Array.method_defined?(method) to_a.send(method, *args, &block) + elsif @klass.respond_to?(method) + @klass.send(:with_scope, self) { @klass.send(method, *args, &block) } elsif arel.respond_to?(method) arel.send(method, *args, &block) elsif match = DynamicFinderMatch.match(method) -- cgit v1.2.3 From 4afd9702fe111a5cbaa0d9572e7661c90b188d49 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Fri, 22 Jan 2010 20:14:37 +0530 Subject: Relation should respond to class methods --- activerecord/lib/active_record/relation.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index fa99e3f891..1a96cdad17 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -32,7 +32,7 @@ module ActiveRecord end def respond_to?(method, include_private = false) - return true if arel.respond_to?(method, include_private) || Array.method_defined?(method) + return true if arel.respond_to?(method, include_private) || Array.method_defined?(method) || @klass.respond_to?(method, include_private) if match = DynamicFinderMatch.match(method) return true if @klass.send(:all_attributes_exists?, match.attribute_names) -- cgit v1.2.3 From 8ff2fb6f3aa6140f5a8bd018d5919a8a1e707cda Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sat, 23 Jan 2010 13:40:38 +0530 Subject: Make default_scope work with Relations --- activerecord/lib/active_record/base.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index f1b2b3b979..12feef4849 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1236,7 +1236,7 @@ module ActiveRecord #:nodoc: end def construct_finder_arel(options = {}, scope = nil) - relation = unscoped.apply_finder_options(options) + relation = options.is_a?(Hash) ? unscoped.apply_finder_options(options) : unscoped.merge(options) relation = scope.merge(relation) if scope relation end @@ -1450,7 +1450,8 @@ module ActiveRecord #:nodoc: end def scoped_methods #:nodoc: - Thread.current[:"#{self}_scoped_methods"] ||= self.default_scoping.dup + key = :"#{self}_scoped_methods" + Thread.current[key] = Thread.current[key].presence || self.default_scoping.dup end def current_scoped_methods #:nodoc: -- cgit v1.2.3