Skip to content

Commit db82002

Browse files
committed
Add adapter option disallowing foreign keys
1 parent be400c3 commit db82002

File tree

6 files changed

+74
-8
lines changed

6 files changed

+74
-8
lines changed

activerecord/CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
* Add adapter option disallowing foreign keys
2+
3+
This adds a new option to be added to `database.yml` which enables skipping
4+
foreign key constraints usage even if the underlying database supports them.
5+
6+
Usage:
7+
```yaml
8+
development:
9+
<<: *default
10+
database: db/development.sqlite3
11+
foreign_keys: false
12+
```
13+
14+
*Paulo Barros*
15+
116
* Add configurable deprecation warning for singular associations
217
318
This adds a deprecation warning when using the plural name of a singular associations in `where`.

activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ def accept(o)
1414
end
1515

1616
delegate :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
17-
:options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?,
18-
:quoted_columns_for_index, :supports_partial_index?, :supports_check_constraints?, :supports_exclusion_constraints?,
19-
to: :@conn, private: true
17+
:options_include_default?, :supports_indexes_in_create?, :use_foreign_keys?,
18+
:quoted_columns_for_index, :supports_partial_index?, :supports_check_constraints?,
19+
:supports_exclusion_constraints?, to: :@conn, private: true
2020

2121
private
2222
def visit_AlterTable(o)
@@ -51,7 +51,7 @@ def visit_TableDefinition(o)
5151
statements.concat(o.indexes.map { |column_name, options| index_in_create(o.name, column_name, options) })
5252
end
5353

54-
if supports_foreign_keys?
54+
if use_foreign_keys?
5555
statements.concat(o.foreign_keys.map { |fk| accept fk })
5656
end
5757

activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,7 +1074,7 @@ def foreign_keys(table_name)
10741074
# (PostgreSQL only) Specify whether or not the foreign key should be deferrable. Valid values are booleans or
10751075
# +:deferred+ or +:immediate+ to specify the default behavior. Defaults to +false+.
10761076
def add_foreign_key(from_table, to_table, **options)
1077-
return unless supports_foreign_keys?
1077+
return unless use_foreign_keys?
10781078
return if options[:if_not_exists] == true && foreign_key_exists?(from_table, to_table)
10791079

10801080
options = foreign_key_options(from_table, to_table, options)
@@ -1115,7 +1115,7 @@ def add_foreign_key(from_table, to_table, **options)
11151115
# [<tt>:to_table</tt>]
11161116
# The name of the table that contains the referenced primary key.
11171117
def remove_foreign_key(from_table, to_table = nil, **options)
1118-
return unless supports_foreign_keys?
1118+
return unless use_foreign_keys?
11191119
return if options.delete(:if_exists) == true && !foreign_key_exists?(from_table, to_table)
11201120

11211121
fk_name_to_delete = foreign_key_for!(from_table, to_table: to_table, **options).name
@@ -1394,6 +1394,10 @@ def create_schema_dumper(options) # :nodoc:
13941394
SchemaDumper.create(self, options)
13951395
end
13961396

1397+
def use_foreign_keys?
1398+
supports_foreign_keys? && foreign_keys_enabled?
1399+
end
1400+
13971401
private
13981402
def validate_change_column_null_argument!(value)
13991403
unless value == true || value == false
@@ -1548,7 +1552,7 @@ def foreign_key_name(table_name, options)
15481552
end
15491553

15501554
def foreign_key_for(from_table, **options)
1551-
return unless supports_foreign_keys?
1555+
return unless use_foreign_keys?
15521556
foreign_keys(from_table).detect { |fk| fk.defined_for?(**options) }
15531557
end
15541558

@@ -1565,6 +1569,10 @@ def extract_foreign_key_action(specifier)
15651569
end
15661570
end
15671571

1572+
def foreign_keys_enabled?
1573+
@config.fetch(:foreign_keys, true)
1574+
end
1575+
15681576
def check_constraint_name(table_name, **options)
15691577
options.fetch(:name) do
15701578
expression = options.fetch(:expression)

activerecord/lib/active_record/schema_dumper.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ def tables(stream)
116116
end
117117

118118
# dump foreign keys at the end to make sure all dependent tables exist.
119-
if @connection.supports_foreign_keys?
119+
if @connection.use_foreign_keys?
120120
sorted_tables.each do |tbl|
121121
foreign_keys(tbl, stream) unless ignored?(tbl)
122122
end

activerecord/test/cases/migration/foreign_key_test.rb

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,34 @@ def test_schema_dumping_with_defferable_initially_immediate
554554
end
555555
end
556556

557+
def test_does_not_create_foreign_keys_when_bypassed_by_config
558+
connection = ActiveRecord::Base.establish_connection(
559+
{
560+
adapter: "sqlite3",
561+
database: "test/db/test.sqlite3",
562+
foreign_keys: false,
563+
}
564+
).connection
565+
566+
connection.create_table "rockets", force: true do |t|
567+
t.string :name
568+
end
569+
connection.create_table "astronauts", force: true do |t|
570+
t.string :name
571+
t.references :rocket
572+
end
573+
574+
connection.add_foreign_key :astronauts, :rockets
575+
576+
foreign_keys = connection.foreign_keys("astronauts")
577+
assert_equal 0, foreign_keys.size
578+
ensure
579+
connection.drop_table "astronauts", if_exists: true rescue nil
580+
connection.drop_table "rockets", if_exists: true rescue nil
581+
582+
ActiveRecord::Base.establish_connection(:arunit)
583+
end
584+
557585
def test_schema_dumping
558586
@connection.add_foreign_key :astronauts, :rockets
559587
output = dump_table_schema "astronauts"

activerecord/test/cases/schema_dumper_test.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,21 @@ def test_do_not_dump_foreign_keys_for_ignored_tables
416416
output = dump_table_schema "authors"
417417
assert_equal ["authors"], output.scan(/^\s*add_foreign_key "([^"]+)".+$/).flatten
418418
end
419+
420+
def test_do_not_dump_foreign_keys_when_bypassed_by_config
421+
ActiveRecord::Base.establish_connection(
422+
{
423+
adapter: "sqlite3",
424+
database: "test/db/test.sqlite3",
425+
foreign_keys: false,
426+
}
427+
)
428+
429+
output = perform_schema_dump
430+
assert_no_match(/^\s+add_foreign_key "fk_test_has_fk"[^\n]+\n\s+add_foreign_key "lessons_students"/, output)
431+
ensure
432+
ActiveRecord::Base.establish_connection(:arunit)
433+
end
419434
end
420435

421436
class CreateDogMigration < ActiveRecord::Migration::Current

0 commit comments

Comments
 (0)