Class: ActiveRecord::ConnectionAdapters::TableDefinition

Inherits:
Object
  • Object
show all
Includes:
ColumnMethods
Defined in:
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.0]
  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

Constructor Details

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

Returns a new instance of TableDefinition.



367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 367

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.



365
366
367
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 365

def as
  @as
end

#check_constraintsObject (readonly)

Returns the value of attribute check_constraints.



365
366
367
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 365

def check_constraints
  @check_constraints
end

#commentObject (readonly)

Returns the value of attribute comment.



365
366
367
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 365

def comment
  @comment
end

#foreign_keysObject (readonly)

Returns the value of attribute foreign_keys.



365
366
367
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 365

def foreign_keys
  @foreign_keys
end

#if_not_existsObject (readonly)

Returns the value of attribute if_not_exists.



365
366
367
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 365

def if_not_exists
  @if_not_exists
end

#indexesObject (readonly)

Returns the value of attribute indexes.



365
366
367
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 365

def indexes
  @indexes
end

#nameObject (readonly)

Returns the value of attribute name.



365
366
367
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 365

def name
  @name
end

#optionsObject (readonly)

Returns the value of attribute options.



365
366
367
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 365

def options
  @options
end

#temporaryObject (readonly)

Returns the value of attribute temporary.



365
366
367
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 365

def temporary
  @temporary
end

Instance Method Details

#[](name) ⇒ Object

Returns a ColumnDefinition for the column with name name.



417
418
419
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 417

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

#check_constraint(expression, **options) ⇒ Object



521
522
523
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 521

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


488
489
490
491
492
493
494
495
496
497
498
499
500
501
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 488

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.



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

def columns; @columns_hash.values; end

#foreign_key(to_table, **options) ⇒ Object



517
518
519
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 517

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')


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

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

#new_check_constraint_definition(expression, options) ⇒ Object

:nodoc:



579
580
581
582
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 579

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:



554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 554

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:



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

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:



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

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.



547
548
549
550
551
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 547

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)


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

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

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



391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 391

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


529
530
531
532
533
534
535
536
537
538
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 529

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