提交 d3fd4e4e 编写于 作者: D David Stosik

Expose foreign key name ignore pattern in configuration

When dumping the database schema, Rails will dump foreign key names only
if those names were not generate by Rails. Currently this is determined
by checking if the foreign key name is `fk_rails_` followed by
a 10-character hash.

At [Cookpad](https://github.com/cookpad), we use
[Departure](https://github.com/departurerb/departure) (Percona's
pt-online-schema-change runner for ActiveRecord migrations) to run migrations.
Often, `pt-osc` will make a copy of a table in order to run a long migration
without blocking it. In this copy process, foreign keys are copied too,
but [their name is prefixed with an underscore to prevent name collision
](https://www.percona.com/doc/percona-toolkit/LATEST/pt-online-schema-change.html#cmdoption-pt-online-schema-change-alter-foreign-keys-method).

In the process described above, we often end up with a development
database that contains foreign keys which name starts with `_fk_rails_`.
That name does not match the ignore pattern, so next time Rails dumps
the database schema (eg. when running `rake db:migrate`), our
`db/schema.rb` file ends up containing those unwanted foreign key names.
This also produces an unwanted git diff that we'd prefer not to commit.

In this PR, I'd like to suggest a way to expose the foreign key name
ignore pattern to the Rails configuration, so that individual projects
can decide on a different pattern of foreign keys that will not get
their names dumped in `schema.rb`.
上级 d7b72761
......@@ -42,6 +42,7 @@ module ActiveRecord
autoload :CounterCache
autoload :DynamicMatchers
autoload :Enum
autoload :ForeignKeys
autoload :InternalMetadata
autoload :Explain
autoload :Inheritance
......
......@@ -101,6 +101,10 @@ def validate?
end
alias validated? validate?
def export_name_on_schema_dump?
name !~ ActiveRecord::Base.fk_ignore_pattern
end
def defined_for?(to_table_ord = nil, to_table: nil, **options)
if to_table_ord
self.to_table == to_table_ord.to_s
......
......@@ -1324,7 +1324,7 @@ def foreign_key_name(table_name, options)
identifier = "#{table_name}_#{options.fetch(:column)}_fk"
hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
"fk_rails_#{hashed_identifier}"
"#{ActiveRecord::ForeignKeys::PREFIX}_#{hashed_identifier}"
end
end
......
......@@ -125,6 +125,8 @@ def self.configurations
mattr_accessor :belongs_to_required_by_default, instance_accessor: false
mattr_accessor :fk_ignore_pattern, instance_accessor: false
class_attribute :default_connection_handler, instance_writer: false
def self.connection_handler
......
# frozen_string_literal: true
module ActiveRecord
module ForeignKeys
# The prefix used by Rails to name unnamed foreign keys.
PREFIX = "fk_rails"
# Default regular expression used by Rails to determine if a foreign key
# name was generated.
DEFAULT_IGNORE_PATTERN = /^#{PREFIX}_[0-9a-f]{10}$/
end
end
......@@ -27,6 +27,7 @@ class Railtie < Rails::Railtie # :nodoc:
config.active_record.use_schema_cache_dump = true
config.active_record.maintain_test_schema = true
config.active_record.fk_ignore_pattern = ActiveRecord::ForeignKeys::DEFAULT_IGNORE_PATTERN
config.active_record.sqlite3 = ActiveSupport::OrderedOptions.new
config.active_record.sqlite3.represent_boolean_as_integer = nil
......
......@@ -210,7 +210,7 @@ def foreign_keys(table, stream)
parts << "primary_key: #{foreign_key.primary_key.inspect}"
end
if foreign_key.name !~ /^fk_rails_[0-9a-f]{10}$/
if foreign_key.export_name_on_schema_dump?
parts << "name: #{foreign_key.name.inspect}"
end
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册