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.



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

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.



369
370
371
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 369

def as
  @as
end

#check_constraintsObject (readonly)

Returns the value of attribute check_constraints.



369
370
371
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 369

def check_constraints
  @check_constraints
end

#commentObject (readonly)

Returns the value of attribute comment.



369
370
371
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 369

def comment
  @comment
end

#foreign_keysObject (readonly)

Returns the value of attribute foreign_keys.



369
370
371
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 369

def foreign_keys
  @foreign_keys
end

#if_not_existsObject (readonly)

Returns the value of attribute if_not_exists.



369
370
371
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 369

def if_not_exists
  @if_not_exists
end

#indexesObject (readonly)

Returns the value of attribute indexes.



369
370
371
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 369

def indexes
  @indexes
end

#nameObject (readonly)

Returns the value of attribute name.



369
370
371
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 369

def name
  @name
end

#optionsObject (readonly)

Returns the value of attribute options.



369
370
371
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 369

def options
  @options
end

#temporaryObject (readonly)

Returns the value of attribute temporary.



369
370
371
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 369

def temporary
  @temporary
end

Instance Method Details

#[](name) ⇒ Object

Returns a ColumnDefinition for the column with name name.



421
422
423
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 421

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

#check_constraint(expression, **options) ⇒ Object



525
526
527
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 525

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


492
493
494
495
496
497
498
499
500
501
502
503
504
505
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 492

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.



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

def columns; @columns_hash.values; end

#foreign_key(to_table, **options) ⇒ Object



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

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


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

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

#new_check_constraint_definition(expression, options) ⇒ Object

:nodoc:



583
584
585
586
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 583

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:



558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 558

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:



575
576
577
578
579
580
581
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 575

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:



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

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.



551
552
553
554
555
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 551

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)


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

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

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



395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 395

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


533
534
535
536
537
538
539
540
541
542
# File 'lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 533

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