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.



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

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.



361
362
363
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 361

def as
  @as
end

#check_constraintsObject (readonly)

Returns the value of attribute check_constraints.



361
362
363
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 361

def check_constraints
  @check_constraints
end

#commentObject (readonly)

Returns the value of attribute comment.



361
362
363
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 361

def comment
  @comment
end

#foreign_keysObject (readonly)

Returns the value of attribute foreign_keys.



361
362
363
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 361

def foreign_keys
  @foreign_keys
end

#if_not_existsObject (readonly)

Returns the value of attribute if_not_exists.



361
362
363
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 361

def if_not_exists
  @if_not_exists
end

#indexesObject (readonly)

Returns the value of attribute indexes.



361
362
363
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 361

def indexes
  @indexes
end

#nameObject (readonly)

Returns the value of attribute name.



361
362
363
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 361

def name
  @name
end

#optionsObject (readonly)

Returns the value of attribute options.



361
362
363
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 361

def options
  @options
end

#temporaryObject (readonly)

Returns the value of attribute temporary.



361
362
363
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 361

def temporary
  @temporary
end

Instance Method Details

#[](name) ⇒ Object

Returns a ColumnDefinition for the column with name name.



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

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

#check_constraint(expression, **options) ⇒ Object



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

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


484
485
486
487
488
489
490
491
492
493
494
495
496
497
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 484

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.



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

def columns; @columns_hash.values; end

#foreign_key(to_table, **options) ⇒ Object



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

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


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

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

#new_check_constraint_definition(expression, options) ⇒ Object

:nodoc:



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

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:



550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 550

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:



567
568
569
570
571
572
573
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 567

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:



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

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.



543
544
545
546
547
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 543

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)


501
502
503
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 501

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

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



387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 387

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


525
526
527
528
529
530
531
532
533
534
# File 'activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb', line 525

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