Class: ActiveRecord::ConnectionAdapters::TableDefinition

Inherits:
Object
  • Object
show all
Includes:
ColumnMethods
Defined in:
activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb

Overview

Active Record Connection Adapters Table Definition

Represents the schema of an SQL table in an abstract way. This class provides methods for manipulating the schema representation.

Inside migration files, the t object in create_table is actually of this type:

class SomeMigration < ActiveRecord::Migration[8.1]
  def up
    create_table :foo do |t|
      puts t.class  # => "ActiveRecord::ConnectionAdapters::TableDefinition"
    end
  end

  def down
    ...
  end
end

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from ColumnMethods

#primary_key

Methods included from ActiveSupport::Concern

#append_features, #class_methods, extended, #included, #prepend_features, #prepended

Constructor Details

#initialize(conn, name, temporary: false, if_not_exists: false, options: nil, as: nil, comment: nil) ⇒ TableDefinition

Returns a new instance of TableDefinition.



359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 359

def initialize(
  conn,
  name,
  temporary: false,
  if_not_exists: false,
  options: nil,
  as: nil,
  comment: nil,
  **
)
  @conn = conn
  @columns_hash = {}
  @indexes = []
  @foreign_keys = []
  @primary_keys = nil
  @check_constraints = []
  @temporary = temporary
  @if_not_exists = if_not_exists
  @options = options
  @as = as
  @name = name
  @comment = comment
end

Instance Attribute Details

#asObject (readonly)

Returns the value of attribute as.



357
358
359
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 357

def as
  @as
end

#check_constraintsObject (readonly)

Returns the value of attribute check_constraints.



357
358
359
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 357

def check_constraints
  @check_constraints
end

#commentObject (readonly)

Returns the value of attribute comment.



357
358
359
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 357

def comment
  @comment
end

#foreign_keysObject (readonly)

Returns the value of attribute foreign_keys.



357
358
359
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 357

def foreign_keys
  @foreign_keys
end

#if_not_existsObject (readonly)

Returns the value of attribute if_not_exists.



357
358
359
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 357

def if_not_exists
  @if_not_exists
end

#indexesObject (readonly)

Returns the value of attribute indexes.



357
358
359
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 357

def indexes
  @indexes
end

#nameObject (readonly)

Returns the value of attribute name.



357
358
359
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 357

def name
  @name
end

#optionsObject (readonly)

Returns the value of attribute options.



357
358
359
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 357

def options
  @options
end

#temporaryObject (readonly)

Returns the value of attribute temporary.



357
358
359
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 357

def temporary
  @temporary
end

Instance Method Details

#[](name) ⇒ Object

Returns a ColumnDefinition for the column with name name.



409
410
411
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 409

def [](name)
  @columns_hash[name.to_s]
end

#check_constraint(expression, **options) ⇒ Object



513
514
515
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 513

def check_constraint(expression, **options)
  check_constraints << new_check_constraint_definition(expression, options)
end

#column(name, type, index: nil, **options) ⇒ Object

Instantiates a new column for the table. See connection.add_column for available options.

Additional options are:

  • :index - Create an index for the column. Can be either true or an options hash.

This method returns self.

Examples

# Assuming `td` is an instance of TableDefinition
td.column(:granted, :boolean, index: true)

Short-hand examples

Instead of calling #column directly, you can also work with the short-hand definitions for the default types. They use the type as the method name instead of as a parameter and allow for multiple columns to be defined in a single statement.

What can be written like this with the regular calls to column:

create_table :products do |t|
  t.column :shop_id,     :integer
  t.column :creator_id,  :integer
  t.column :item_number, :string
  t.column :name,        :string, default: "Untitled"
  t.column :value,       :string, default: "Untitled"
  t.column :created_at,  :datetime
  t.column :updated_at,  :datetime
end
add_index :products, :item_number

can also be written as follows using the short-hand:

create_table :products do |t|
  t.integer :shop_id, :creator_id
  t.string  :item_number, index: true
  t.string  :name, :value, default: "Untitled"
  t.timestamps null: false
end

There’s a short-hand method for each of the type values declared at the top. And then there’s TableDefinition#timestamps that’ll add created_at and updated_at as datetimes.

TableDefinition#references will add an appropriately-named _id column, plus a corresponding _type column if the :polymorphic option is supplied. If :polymorphic is a hash of options, these will be used when creating the _type column. The :index option will also create an index, similar to calling add_index. So what can be written like this:

create_table :taggings do |t|
  t.integer :tag_id, :tagger_id, :taggable_id
  t.string  :tagger_type
  t.string  :taggable_type, default: 'Photo'
end
add_index :taggings, :tag_id, name: 'index_taggings_on_tag_id'
add_index :taggings, [:tagger_id, :tagger_type]

Can also be written as follows using references:

create_table :taggings do |t|
  t.references :tag, index: { name: 'index_taggings_on_tag_id' }
  t.references :tagger, polymorphic: true
  t.references :taggable, polymorphic: { default: 'Photo' }, index: false
end


480
481
482
483
484
485
486
487
488
489
490
491
492
493
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 480

def column(name, type, index: nil, **options)
  name = name.to_s
  type = type.to_sym if type

  raise_on_duplicate_column(name)
  @columns_hash[name] = new_column_definition(name, type, **options)

  if index
    index_options = index.is_a?(Hash) ? index : {}
    index(name, **index_options)
  end

  self
end

#columnsObject

Returns an array of ColumnDefinition objects for the columns of the table.



406
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 406

def columns; @columns_hash.values; end

#foreign_key(to_table, **options) ⇒ Object



509
510
511
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 509

def foreign_key(to_table, **options)
  foreign_keys << new_foreign_key_definition(to_table, options)
end

#index(column_name, **options) ⇒ Object

Adds index options to the indexes hash, keyed by column name This is primarily used to track indexes that need to be created after the table

index(:account_id, name: 'index_projects_on_account_id')


505
506
507
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 505

def index(column_name, **options)
  indexes << [column_name, options]
end

#new_check_constraint_definition(expression, options) ⇒ Object

:nodoc:



571
572
573
574
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 571

def new_check_constraint_definition(expression, options) # :nodoc:
  options = @conn.check_constraint_options(name, expression, options)
  CheckConstraintDefinition.new(name, expression, options)
end

#new_column_definition(name, type, **options) ⇒ Object

:nodoc:



546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 546

def new_column_definition(name, type, **options) # :nodoc:
  if integer_like_primary_key?(type, options)
    type = integer_like_primary_key_type(type, options)
  end
  type = aliased_types(type.to_s, type)

  if @conn.supports_datetime_with_precision?
    if type == :datetime && !options.key?(:precision)
      options[:precision] = 6
    end
  end

  options[:primary_key] ||= type == :primary_key
  options[:null] = false if options[:primary_key]
  create_column_definition(name, type, options)
end

#new_foreign_key_definition(to_table, options) ⇒ Object

:nodoc:



563
564
565
566
567
568
569
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 563

def new_foreign_key_definition(to_table, options) # :nodoc:
  prefix = ActiveRecord::Base.table_name_prefix
  suffix = ActiveRecord::Base.table_name_suffix
  to_table = "#{prefix}#{to_table}#{suffix}"
  options = @conn.foreign_key_options(name, to_table, options)
  ForeignKeyDefinition.new(name, to_table, options)
end

#primary_keys(name = nil) ⇒ Object

:nodoc:



400
401
402
403
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 400

def primary_keys(name = nil) # :nodoc:
  @primary_keys = PrimaryKeyDefinition.new(name) if name
  @primary_keys
end

#references(*args, **options) ⇒ Object Also known as: belongs_to

Adds a reference.

t.references(:user)
t.belongs_to(:supplier, foreign_key: true)
t.belongs_to(:supplier, foreign_key: true, type: :integer)

See connection.add_reference for details of the options you can use.



539
540
541
542
543
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 539

def references(*args, **options)
  args.each do |ref_name|
    ReferenceDefinition.new(ref_name, **options).add_to(self)
  end
end

#remove_column(name) ⇒ Object

remove the column name from the table.

remove_column(:account_id)


497
498
499
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 497

def remove_column(name)
  @columns_hash.delete name.to_s
end

#set_primary_key(table_name, id, primary_key, **options) ⇒ Object



383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 383

def set_primary_key(table_name, id, primary_key, **options)
  if id && !as
    pk = primary_key || Base.get_primary_key(table_name.to_s.singularize)

    if id.is_a?(Hash)
      options.merge!(id.except(:type))
      id = id.fetch(:type, :primary_key)
    end

    if pk.is_a?(Array)
      primary_keys(pk)
    else
      primary_key(pk, id, **options)
    end
  end
end

#timestamps(**options) ⇒ Object

Appends :datetime columns :created_at and :updated_at to the table. See connection.add_timestamps

t.timestamps null: false


521
522
523
524
525
526
527
528
529
530
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 521

def timestamps(**options)
  options[:null] = false if options[:null].nil?

  if !options.key?(:precision) && @conn.supports_datetime_with_precision?
    options[:precision] = 6
  end

  column(:created_at, :datetime, **options)
  column(:updated_at, :datetime, **options)
end