From ceb33f84933639d3b61aac62e5e71fd087ab65ed Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Thu, 15 Dec 2011 20:07:41 +0000 Subject: Split out most of the AR::Base code into separate modules :cake: --- .../lib/active_record/attribute_methods.rb | 115 ++++++++++++++++++++- 1 file changed, 113 insertions(+), 2 deletions(-) (limited to 'activerecord/lib/active_record/attribute_methods.rb') diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index 47f625039b..43ab289bdc 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -75,6 +75,21 @@ module ActiveRecord !superclass.method_defined?(method_name) && !superclass.private_method_defined?(method_name) end + + def attribute_method?(attribute) + super || (table_exists? && column_names.include?(attribute.to_s.sub(/=$/, ''))) + end + + # Returns an array of column names as strings if it's not + # an abstract class and table exists. + # Otherwise it returns an empty array. + def attribute_names + @attribute_names ||= if !abstract_class? && table_exists? + column_names + else + [] + end + end end # If we haven't generated any methods yet, generate them, then @@ -112,9 +127,105 @@ module ActiveRecord super 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. + def attribute_names + @attributes.keys + end + + # Returns a hash of all the attributes with their names as keys and the values of the attributes as values. + def attributes + Hash[@attributes.map { |name, _| [name, read_attribute(name)] }] + end + + # Returns an #inspect-like string for the value of the + # attribute +attr_name+. String attributes are truncated upto 50 + # characters, and Date and Time attributes are returned in the + # :db format. Other attributes return the value of + # #inspect without modification. + # + # person = Person.create!(:name => "David Heinemeier Hansson " * 3) + # + # person.attribute_for_inspect(:name) + # # => '"David Heinemeier Hansson David Heinemeier Hansson D..."' + # + # person.attribute_for_inspect(:created_at) + # # => '"2009-01-12 04:48:57"' + def attribute_for_inspect(attr_name) + value = read_attribute(attr_name) + + if value.is_a?(String) && value.length > 50 + "#{value[0..50]}...".inspect + elsif value.is_a?(Date) || value.is_a?(Time) + %("#{value.to_s(:db)}") + else + value.inspect + end + end + + # Returns true if the specified +attribute+ has been set by the user or by a database load and is neither + # nil nor empty? (the latter only applies to objects that respond to empty?, most notably Strings). + def attribute_present?(attribute) + value = read_attribute(attribute) + !value.nil? || (value.respond_to?(:empty?) && !value.empty?) + end + + # Returns the column object for the named attribute. + def column_for_attribute(name) + self.class.columns_hash[name.to_s] + end + protected - def attribute_method?(attr_name) - attr_name == 'id' || (defined?(@attributes) && @attributes.include?(attr_name)) + + def clone_attributes(reader_method = :read_attribute, attributes = {}) + attribute_names.each do |name| + attributes[name] = clone_attribute_value(reader_method, name) + end + attributes + end + + def clone_attribute_value(reader_method, attribute_name) + value = send(reader_method, attribute_name) + value.duplicable? ? value.clone : value + rescue TypeError, NoMethodError + value + end + + # Returns a copy of the attributes hash where all the values have been safely quoted for use in + # an Arel insert/update method. + def arel_attributes_values(include_primary_key = true, include_readonly_attributes = true, attribute_names = @attributes.keys) + attrs = {} + klass = self.class + arel_table = klass.arel_table + + attribute_names.each do |name| + if (column = column_for_attribute(name)) && (include_primary_key || !column.primary) + + if include_readonly_attributes || !self.class.readonly_attributes.include?(name) + + value = if klass.serialized_attributes.include?(name) + @attributes[name].serialized_value + else + # FIXME: we need @attributes to be used consistently. + # If the values stored in @attributes were already type + # casted, this code could be simplified + read_attribute(name) + end + + attrs[arel_table[name]] = value + end + end end + + attrs + end + + def attribute_method?(attr_name) + attr_name == 'id' || (defined?(@attributes) && @attributes.include?(attr_name)) + end end end -- cgit v1.2.3