class Whiteprint::Adapters::ActiveRecord

Constants

BELONGS_TO_OPTIONS

Public Class Methods

applicable?(model) click to toggle source
# File lib/whiteprint/adapters/active_record.rb, line 12
def applicable?(model)
  return false unless defined?(::ActiveRecord)
  model < ::ActiveRecord::Base
end
camelize(name) click to toggle source
# File lib/whiteprint/adapters/active_record.rb, line 22
def camelize(name)
  name = underscore(name)
  name = name.gsub(/^([a-z])/) { Regexp.last_match[1].upcase }
  name.gsub(/_([a-zA-Z])/) { Regexp.last_match[1].upcase }
end
generate_migration(name, trees) click to toggle source
# File lib/whiteprint/adapters/active_record.rb, line 28
def generate_migration(name, trees)
  filename = "#{Time.now.strftime('%Y%m%d%H%M%S')}_#{underscore(name)}.rb"
  path     = File.join(Whiteprint.config.migration_path, filename)
  File.open(path, 'w') do |f|
    f.write migration(name, trees)
  end
  path
end
migrate() click to toggle source
# File lib/whiteprint/adapters/active_record.rb, line 37
def migrate
  ::ActiveRecord::Migration.verbose = true
  ::ActiveRecord::Migrator.migrate(::ActiveRecord::Migrator.migrations_paths)
end
migration(name, trees) click to toggle source
# File lib/whiteprint/adapters/active_record.rb, line 42
def migration(name, trees)
  "class #{camelize(name)} < ActiveRecord::Migration\n  def change\n" + transform(trees) + "  end\nend\n"
end
migration_params(cli) click to toggle source
# File lib/whiteprint/adapters/active_record.rb, line 46
def migration_params(cli)
  name = cli.ask 'How would you like to name this migration?'
  [name]
end
name() click to toggle source
# File lib/whiteprint/adapters/active_record.rb, line 118
def name
  "#{@join_table}_habtm_model"
end
new(model, id: true, timestamps: true, auto_belongs_to: true, **_options) click to toggle source
Calls superclass method Whiteprint::Base::new
# File lib/whiteprint/adapters/active_record.rb, line 58
def initialize(model, id: true, timestamps: true, auto_belongs_to: true, **_options)
  super(model, id: true, timestamps: true, **_options)

  @has_id          = id
  @has_timestamps  = timestamps
  @auto_belongs_to = auto_belongs_to
  @attributes.add(name: :id, type: :integer, null: false) if id
  @attributes.add(name: :created_at, type: :datetime)     if timestamps
  @attributes.add(name: :updated_at, type: :datetime)     if timestamps
end
table_exists?() click to toggle source
# File lib/whiteprint/adapters/active_record.rb, line 126
def table_exists?
  ::ActiveRecord::Base.connection.table_exists?(table_name)
end
table_name() click to toggle source
# File lib/whiteprint/adapters/active_record.rb, line 122
def table_name
  @join_table
end
underscore(name) click to toggle source
# File lib/whiteprint/adapters/active_record.rb, line 17
def underscore(name)
  name = name.tr(' ', '_')
  name.gsub(/([a-z])([A-Z])/) { "#{Regexp.last_match[1]}_#{Regexp.last_match[2].downcase}" }.downcase
end

Private Class Methods

transform(trees) click to toggle source
# File lib/whiteprint/adapters/active_record.rb, line 53
def transform(trees)
  Migration.new.apply(trees).join("\n")
end

Public Instance Methods

accessor(name, options) click to toggle source
# File lib/whiteprint/adapters/active_record.rb, line 69
def accessor(name, options)
  @attributes.add(name: name, type: :accessor, virtual: true, **options)
  model.send :attr_accessor, name
end
changes_tree() click to toggle source
Calls superclass method Whiteprint::Base#changes_tree
# File lib/whiteprint/adapters/active_record.rb, line 74
def changes_tree
  changes_tree = super

  unless changes_tree[:table_exists]
    changes_tree[:has_id] = @has_id
    changes_tree[:attributes].reject! { |attribute| attribute[:name] == :id }
  end

  added_created_at = changes_tree[:attributes].select { |attribute| attribute[:name] == :created_at && attribute[:kind] == :added }
  added_updated_at = changes_tree[:attributes].select { |attribute| attribute[:name] == :updated_at && attribute[:kind] == :added }

  if added_created_at.size == 1 && added_updated_at.size == 1
    changes_tree[:attributes] -= [*added_created_at, *added_updated_at]
    changes_tree[:attributes] += [{ type: :timestamps, kind: :added }]
  end

  changes_tree[:attributes].each do |attribute|
    persisted_attribute = persisted_attributes[attribute[:name]]
    if persisted_attribute && attribute[:options][:default].nil? && persisted_attribute[:options][:default]
      changes_tree[:attributes] += [{ name: attribute[:name], kind: :removed_default }]
    end
  end

  changes_tree
end
habtm(name, **options)
has_and_belongs_to_many(name, **options) click to toggle source
Calls superclass method
# File lib/whiteprint/adapters/active_record.rb, line 100
def has_and_belongs_to_many(name, **options)
  super(name, **options.merge(virtual: true))
  model.send(:has_and_belongs_to_many, name.to_sym, **options) unless model.reflect_on_association(name)

  association = model.reflect_on_association(name)

  Class.new do
    include Whiteprint::Model

    @association = association
    @join_table  = association.join_table

    whiteprint(adapter: :has_and_belongs_to_many, id: false, timestamps: false) do
      integer association.foreign_key
      integer association.association_foreign_key
    end

    class << self
      def name
        "#{@join_table}_habtm_model"
      end

      def table_name
        @join_table
      end

      def table_exists?
        ::ActiveRecord::Base.connection.table_exists?(table_name)
      end
    end
  end
end
Also aliased as: habtm
method_missing(type, name, **options) click to toggle source
Calls superclass method Whiteprint::Base#method_missing
# File lib/whiteprint/adapters/active_record.rb, line 179
def method_missing(type, name, **options)
  super

  if options[:default] && options[:default].is_a?(Symbol)
    model.send :after_initialize do
      next if self.send(name) || !new_record?
      self.send "#{name}=", send(options[:default])
    end
  end
end
migration(name) click to toggle source
# File lib/whiteprint/adapters/active_record.rb, line 134
def migration(name)
  self.class.migration(name, [changes_tree])
end
options_from_column(column) click to toggle source
# File lib/whiteprint/adapters/active_record.rb, line 138
def options_from_column(column)
  [:name, :type, *Whiteprint.config.persisted_attribute_options.keys].map do |option|
    association_by_foreign_key = find_association_by_foreign_key(column)
    overridden_name            = association_by_foreign_key && association_by_foreign_key.name || column.name
    current_attribute          = attributes[overridden_name]

    next {name: overridden_name}               if option == :name        && association_by_foreign_key
    next {type: :references}                   if option == :type        && association_by_foreign_key
    next {polymorphic: true}                   if option == :polymorphic && association_by_foreign_key && model.column_names.include?(association_by_foreign_key.foreign_type)
    next                                       unless column.respond_to?(option)
    next {default: current_attribute.default}  if option == :default && current_attribute && current_attribute.default.is_a?(Symbol)

    value = column.send(option)
    value = column.type_cast_from_database(value) if option == :default
    next if value == Whiteprint.config.persisted_attribute_options[option]
    { option => value }
  end.compact.inject(&:merge)
end
persisted_attributes() click to toggle source
# File lib/whiteprint/adapters/active_record.rb, line 157
def persisted_attributes
  attributes = Whiteprint::Attributes.new
  return attributes unless table_exists?
  model.columns.each do |column|
    next if find_association_by_foreign_type(column)

    attributes.add options_from_column(column)
  end
  attributes.for_persisted
end
references(name, **options) click to toggle source
Calls superclass method
# File lib/whiteprint/adapters/active_record.rb, line 168
def references(name, **options)
  super
  return unless @auto_belongs_to
  model.send :belongs_to, name.to_sym, **options.slice(*BELONGS_TO_OPTIONS)
end
table_exists?() click to toggle source
# File lib/whiteprint/adapters/active_record.rb, line 174
def table_exists?
  model.connection.schema_cache.clear!
  model.connection.table_exists?(table_name)
end

Private Instance Methods

find_association_by_foreign_key(column) click to toggle source
# File lib/whiteprint/adapters/active_record.rb, line 192
def find_association_by_foreign_key(column)
  model.reflect_on_all_associations.find do |association|
    association.foreign_key == column.name
  end
end
find_association_by_foreign_type(column) click to toggle source
# File lib/whiteprint/adapters/active_record.rb, line 198
def find_association_by_foreign_type(column)
  model.reflect_on_all_associations.find do |association|
    association.polymorphic? && association.foreign_type.to_s == column.name.to_s
  end
end