class Migrant::Schema

Converts the following DSL:

class MyModel < ActiveRecord::Base

structure do
  my_field "some string"
 end

end into a schema on that model class by calling method_missing(my_field) and deciding what the best schema type is for the user's requiredments

Attributes

columns[RW]
indexes[RW]
validations[RW]

Public Class Methods

new() click to toggle source
# File lib/migrant/schema.rb, line 14
def initialize
  @proxy = SchemaProxy.new(self)
  @columns = Hash.new
  @indexes = Array.new
  @validations = Hash.new
  @type = :default
end

Public Instance Methods

add_association(association) click to toggle source
# File lib/migrant/schema.rb, line 30
def add_association(association)
  # Rails 3.1 changes primary_key_name to foreign_key (correct behaviour), so this is essentially backwards compatibility for Rails 3.0
  field = (association.respond_to?(:foreign_key))? association.foreign_key.to_sym : association.primary_key_name.to_sym
  
  case association.macro
    when :belongs_to
      if association.options[:polymorphic]
        @columns[(association.name.to_s+'_type').to_sym] = DataType::Polymorphic.new(:field => field)
        @indexes << [(association.name.to_s+'_type').to_sym, field]
      end
      @columns[field] = DataType::ForeignKey.new(:field => field)
      @indexes << field
  end
end
add_field(field, data_type = nil, options = {}) click to toggle source

This is where we decide what the best schema is based on the structure requirements The output of this is essentially a formatted schema hash that is processed on each model by Migrant::MigrationGenerator

# File lib/migrant/schema.rb, line 62
def add_field(field, data_type = nil, options = {})
  data_type = DataType::String if data_type.nil?
  puts [":#{field}", "#{data_type.class.to_s}", "#{options.inspect}"].collect { |s| s.ljust(25) }.join if ENV['DEBUG']
  
  # Fields that do special things go here.
  if field == :timestamps
    add_field(:updated_at, :datetime)
    add_field(:created_at, :datetime)
    return true
  end

  # Add index if explicitly asked
  @indexes << field if options.delete(:index) || data_type.class.to_s == 'Hash' && data_type.delete(:index)
  @validations[field] = options.delete(:validates) if options[:validates]
  options.merge!(:field => field)    
  
  # Matches: description DataType::Paragraph, :index => true
  if data_type.is_a?(Class) && data_type.respond_to?(:migrant_data_type?)
    @columns[field] = data_type.new(options)
  # Matches: description :index => true, :unique => true
  else
    begin
      # Eg. "My field" -> String -> DataType::String
      @columns[field] = "DataType::#{data_type.class.to_s}".constantize.new(options.merge(:value => data_type))
    rescue NameError
      # We don't have a matching type, throw a warning and default to string
      puts "MIGRATION WARNING: No migration implementation for class #{data_type.class.to_s} on field '#{field}', defaulting to string..."
      @columns[field] = DataType::Base.new(options)
    end
  end
end
column_migrations() click to toggle source
# File lib/migrant/schema.rb, line 54
def column_migrations
  @columns.collect {|field, data| [field, data.column] } # All that needs to be migrated
end
define_structure(type, &block) click to toggle source
# File lib/migrant/schema.rb, line 22
def define_structure(type, &block)
  @validations = Hash.new
  @type = type if type

  # Runs method_missing on columns given in the model "structure" DSL
  @proxy.translate_fancy_dsl(&block) if block_given?
end
partial?() click to toggle source

If the user defines structure(:partial), irreversible changes are ignored (removing a column, for example)

# File lib/migrant/schema.rb, line 50
def partial?
  @type == :partial
end
requires_migration?() click to toggle source
# File lib/migrant/schema.rb, line 45
def requires_migration?
  true
end