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[7.2]
  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.



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

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.



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

def as
  @as
end

#check_constraintsObject (readonly)

Returns the value of attribute check_constraints.



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

def check_constraints
  @check_constraints
end

#commentObject (readonly)

Returns the value of attribute comment.



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

def comment
  @comment
end

#foreign_keysObject (readonly)

Returns the value of attribute foreign_keys.



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

def foreign_keys
  @foreign_keys
end

#if_not_existsObject (readonly)

Returns the value of attribute if_not_exists.



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

def if_not_exists
  @if_not_exists
end

#indexesObject (readonly)

Returns the value of attribute indexes.



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

def indexes
  @indexes
end

#nameObject (readonly)

Returns the value of attribute name.



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

def name
  @name
end

#optionsObject (readonly)

Returns the value of attribute options.



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

def options
  @options
end

#temporaryObject (readonly)

Returns the value of attribute temporary.



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

def temporary
  @temporary
end

Instance Method Details

#[](name) ⇒ Object

Returns a ColumnDefinition for the column with name name.



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

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

#check_constraint(expression, **options) ⇒ Object



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

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


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

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.



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

def columns; @columns_hash.values; end

#foreign_key(to_table, **options) ⇒ Object



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

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


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

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

#new_check_constraint_definition(expression, options) ⇒ Object

:nodoc:



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

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:



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

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:



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

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:



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

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.



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

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)


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

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

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



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

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


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

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