mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Add a foreign_key
option to references
while creating the table
Rather than having to do: create_table :posts do |t| t.references :user end add_foreign_key :posts, :users You can instead do: create_table :posts do |t| t.references :user, foreign_key: true end Similar to the `index` option, you can also pass a hash. This will be passed as the options to `add_foreign_key`. e.g.: create_table :posts do |t| t.references :user, foreign_key: { primary_key: :other_id } end is equivalent to create_table :posts do |t| t.references :user end add_foreign_key :posts, :users, primary_key: :other_id
This commit is contained in:
parent
a9c0c46263
commit
99a6f9e60e
3 changed files with 94 additions and 5 deletions
|
@ -94,11 +94,12 @@ module ActiveRecord
|
|||
# An array of ColumnDefinition objects, representing the column changes
|
||||
# that have been defined.
|
||||
attr_accessor :indexes
|
||||
attr_reader :name, :temporary, :options, :as
|
||||
attr_reader :name, :temporary, :options, :as, :foreign_keys
|
||||
|
||||
def initialize(types, name, temporary, options, as = nil)
|
||||
@columns_hash = {}
|
||||
@indexes = {}
|
||||
@foreign_keys = {}
|
||||
@native = types
|
||||
@temporary = temporary
|
||||
@options = options
|
||||
|
@ -286,6 +287,10 @@ module ActiveRecord
|
|||
indexes[column_name] = options
|
||||
end
|
||||
|
||||
def foreign_key(table_name, options = {}) # :nodoc:
|
||||
foreign_keys[table_name] = options
|
||||
end
|
||||
|
||||
# Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
|
||||
# <tt>:updated_at</tt> to the table. See SchemaStatements#add_timestamps
|
||||
#
|
||||
|
@ -297,9 +302,12 @@ module ActiveRecord
|
|||
column(:updated_at, :datetime, options)
|
||||
end
|
||||
|
||||
# Adds a reference. Optionally adds a +type+ column, if <tt>:polymorphic</tt> option is provided.
|
||||
# <tt>references</tt> and <tt>belongs_to</tt> are acceptable. The reference column will be an +integer+
|
||||
# by default, the <tt>:type</tt> option can be used to specify a different type.
|
||||
# Adds a reference. Optionally adds a +type+ column, if
|
||||
# <tt>:polymorphic</tt> option is provided. <tt>references</tt> and
|
||||
# <tt>belongs_to</tt> are acceptable. The reference column will be an
|
||||
# +integer+ by default, the <tt>:type</tt> option can be used to specify
|
||||
# a different type. A foreign key will be created if a +foreign_key+
|
||||
# option is passed.
|
||||
#
|
||||
# t.references(:user)
|
||||
# t.references(:user, type: "string")
|
||||
|
@ -310,11 +318,18 @@ module ActiveRecord
|
|||
*args,
|
||||
polymorphic: false,
|
||||
index: false,
|
||||
foreign_key: false,
|
||||
type: :integer,
|
||||
**options
|
||||
)
|
||||
polymorphic_options = polymorphic.is_a?(Hash) ? polymorphic : options
|
||||
index_options = index.is_a?(Hash) ? index : {}
|
||||
foreign_key_options = foreign_key.is_a?(Hash) ? foreign_key : {}
|
||||
|
||||
if polymorphic && foreign_key
|
||||
raise ArgumentError, "Cannot add a foreign key on a polymorphic relation"
|
||||
end
|
||||
|
||||
args.each do |col|
|
||||
column("#{col}_id", type, options)
|
||||
|
||||
|
@ -325,6 +340,10 @@ module ActiveRecord
|
|||
if index
|
||||
self.index(polymorphic ? %w(type id).map { |t| "#{col}_#{t}" } : "#{col}_id", index_options)
|
||||
end
|
||||
|
||||
if foreign_key
|
||||
self.foreign_key(col.to_s.pluralize, foreign_key_options)
|
||||
end
|
||||
end
|
||||
end
|
||||
alias :belongs_to :references
|
||||
|
|
|
@ -204,7 +204,17 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
result = execute schema_creation.accept td
|
||||
td.indexes.each_pair { |c, o| add_index(table_name, c, o) } unless supports_indexes_in_create?
|
||||
|
||||
unless supports_indexes_in_create?
|
||||
td.indexes.each_pair do |column_name, index_options|
|
||||
add_index(table_name, column_name, index_options)
|
||||
end
|
||||
end
|
||||
|
||||
td.foreign_keys.each_pair do |other_table_name, foreign_key_options|
|
||||
add_foreign_key(table_name, other_table_name, foreign_key_options)
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
require 'cases/helper'
|
||||
|
||||
if ActiveRecord::Base.connection.supports_foreign_keys?
|
||||
module ActiveRecord
|
||||
class Migration
|
||||
class ReferencesForeignKeyTest < ActiveRecord::TestCase
|
||||
setup do
|
||||
@connection = ActiveRecord::Base.connection
|
||||
@connection.transaction do
|
||||
@connection.create_table(:testing_parents, force: true)
|
||||
end
|
||||
end
|
||||
|
||||
teardown do
|
||||
@connection.execute("drop table if exists testings")
|
||||
@connection.execute("drop table if exists testing_parents")
|
||||
end
|
||||
|
||||
test "foreign keys can be created with the table" do
|
||||
@connection.create_table :testings do |t|
|
||||
t.references :testing_parent, foreign_key: true
|
||||
end
|
||||
|
||||
fk = @connection.foreign_keys("testings").first
|
||||
assert_equal "testings", fk.from_table
|
||||
assert_equal "testing_parents", fk.to_table
|
||||
end
|
||||
|
||||
test "no foreign key is created by default" do
|
||||
@connection.create_table :testings do |t|
|
||||
t.references :testing_parent
|
||||
end
|
||||
|
||||
assert_equal [], @connection.foreign_keys("testings")
|
||||
end
|
||||
|
||||
test "options hash can be passed" do
|
||||
@connection.change_table :testing_parents do |t|
|
||||
t.integer :other_id
|
||||
t.index :other_id, unique: true
|
||||
end
|
||||
@connection.create_table :testings do |t|
|
||||
t.references :testing_parent, foreign_key: { primary_key: :other_id }
|
||||
end
|
||||
|
||||
fk = @connection.foreign_keys("testings").find { |k| k.to_table == "testing_parents" }
|
||||
assert_equal "other_id", fk.primary_key
|
||||
end
|
||||
|
||||
test "foreign keys cannot be added to polymorphic relations when creating the table" do
|
||||
@connection.create_table :testings do |t|
|
||||
assert_raises(ArgumentError) do
|
||||
t.references :testing_parent, polymorphic: true, foreign_key: true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue