diff options
Diffstat (limited to 'activerecord/lib/active_record/model_schema.rb')
-rw-r--r-- | activerecord/lib/active_record/model_schema.rb | 106 |
1 files changed, 49 insertions, 57 deletions
diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb index dc5ff02882..adad7774b9 100644 --- a/activerecord/lib/active_record/model_schema.rb +++ b/activerecord/lib/active_record/model_schema.rb @@ -29,6 +29,10 @@ module ActiveRecord # :singleton-method: # Works like +table_name_prefix+, but appends instead of prepends (set to "_basecamp" gives "projects_basecamp", # "people_basecamp"). By default, the suffix is the empty string. + # + # If you are organising your models within modules, you can add a suffix to the models within + # a namespace by defining a singleton method in the parent module called table_name_suffix which + # returns your chosen suffix. class_attribute :table_name_suffix, instance_writer: false self.table_name_suffix = "" @@ -47,6 +51,19 @@ module ActiveRecord self.pluralize_table_names = true self.inheritance_column = 'type' + + delegate :type_for_attribute, to: :class + end + + # Derives the join table name for +first_table+ and +second_table+. The + # table names appear in alphabetical order. A common prefix is removed + # (useful for namespaced models like Music::Artist and Music::Record): + # + # artists, records => artists_records + # records, artists => artists_records + # music_artists, music_records => music_artists_records + def self.derive_join_table_name(first_table, second_table) # :nodoc: + [first_table.to_s, second_table.to_s].sort.join("\0").gsub(/^(.*_)(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_") end module ClassMethods @@ -153,6 +170,10 @@ module ActiveRecord (parents.detect{ |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix end + def full_table_name_suffix #:nodoc: + (parents.detect {|p| p.respond_to?(:table_name_suffix) } || self).table_name_suffix + end + # Defines the name of the table column which will store the class name on single-table # inheritance situations. # @@ -190,7 +211,7 @@ module ActiveRecord # given block. This is required for Oracle and is useful for any # database which relies on sequences for primary key generation. # - # If a sequence name is not explicitly set when using Oracle or Firebird, + # If a sequence name is not explicitly set when using Oracle, # it will default to the commonly used pattern of: #{table_name}_seq # # If a sequence name is not explicitly set when using PostgreSQL, it @@ -209,50 +230,29 @@ module ActiveRecord connection.schema_cache.table_exists?(table_name) end - # Returns an array of column objects for the table associated with this class. - def columns - @columns ||= connection.schema_cache.columns(table_name).map do |col| - col = col.dup - col.primary = (col.name == primary_key) - col - end - end - - # Returns a hash of column objects for the table associated with this class. - def columns_hash - @columns_hash ||= Hash[columns.map { |c| [c.name, c] }] + def attributes_builder # :nodoc: + @attributes_builder ||= AttributeSet::Builder.new(column_types, primary_key) end def column_types # :nodoc: - @column_types ||= decorate_columns(columns_hash.dup) - end - - def decorate_columns(columns_hash) # :nodoc: - return if columns_hash.empty? - - @serialized_column_names ||= self.columns_hash.keys.find_all do |name| - serialized_attributes.key?(name) - end - - @serialized_column_names.each do |name| - columns_hash[name] = AttributeMethods::Serialization::Type.new(columns_hash[name]) - end - - @time_zone_column_names ||= self.columns_hash.find_all do |name, col| - create_time_zone_conversion_attribute?(name, col) - end.map!(&:first) - - @time_zone_column_names.each do |name| - columns_hash[name] = AttributeMethods::TimeZoneConversion::Type.new(columns_hash[name]) + @column_types ||= columns_hash.transform_values(&:cast_type).tap do |h| + h.default = Type::Value.new end + end - columns_hash + def type_for_attribute(attr_name) # :nodoc: + column_types[attr_name] end # Returns a hash where the keys are column names and the values are # default values when instantiating the AR object for this table. def column_defaults - @column_defaults ||= Hash[columns.map { |c| [c.name, c.default] }] + _default_attributes.to_hash + end + + def _default_attributes # :nodoc: + @default_attributes ||= attributes_builder.build_from_database( + raw_default_values) end # Returns an array of column names as strings. @@ -263,7 +263,7 @@ module ActiveRecord # Returns an array of column objects where the primary id, all columns ending in "_id" or "_count", # and columns used for single table inheritance have been removed. def content_columns - @content_columns ||= columns.reject { |c| c.primary || c.name =~ /(_id|_count)$/ || c.name == inheritance_column } + @content_columns ||= columns.reject { |c| c.name == primary_key || c.name =~ /(_id|_count)$/ || c.name == inheritance_column } end # Resets all the cached information about columns, which will cause them @@ -297,26 +297,13 @@ module ActiveRecord undefine_attribute_methods connection.schema_cache.clear_table_cache!(table_name) if table_exists? - @arel_engine = nil - @column_defaults = nil - @column_names = nil - @columns = nil - @columns_hash = nil - @column_types = nil - @content_columns = nil - @dynamic_methods_hash = nil - @inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column - @relation = nil - @serialized_column_names = nil - @time_zone_column_names = nil - @cached_time_zone = nil - end - - # This is a hook for use by modules that need to do extra stuff to - # attributes when they are initialized. (e.g. attribute - # serialization) - def initialize_attributes(attributes, options = {}) #:nodoc: - attributes + @arel_engine = nil + @column_names = nil + @column_types = nil + @content_columns = nil + @default_attributes = nil + @inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column + @relation = nil end private @@ -337,12 +324,17 @@ module ActiveRecord contained = contained.singularize if parent.pluralize_table_names contained += '_' end - "#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{table_name_suffix}" + + "#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{full_table_name_suffix}" else # STI subclasses always use their superclass' table. base.table_name end end + + def raw_default_values + columns_hash.transform_values(&:default) + end end end end |