-
Notifications
You must be signed in to change notification settings - Fork 21.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Let t.foreign_key use the same to_table
twice
#23614
Conversation
r? @schneems (@rails-bot has picked a reviewer for you, use r? to override) |
CI has failed, but the error doesn't seem to have anything to do with the changes I made. Here's the failing job and the error is |
@@ -330,7 +330,8 @@ def index(column_name, options = {}) | |||
end | |||
|
|||
def foreign_key(table_name, options = {}) # :nodoc: | |||
foreign_keys[table_name] = options | |||
foreign_keys[table_name] ||= [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think @foreign_keys
should be an array rather than a hash because foreign keys can be added to the same table.
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -212,7 +212,7 @@ module ActiveRecord
def initialize(name, temporary, options, as = nil)
@columns_hash = {}
@indexes = {}
- @foreign_keys = {}
+ @foreign_keys = []
@primary_keys = nil
@temporary = temporary
@options = options
@@ -330,7 +330,7 @@ module ActiveRecord
end
def foreign_key(table_name, options = {}) # :nodoc:
- foreign_keys[table_name] = options
+ foreign_keys << [table_name, options]
end
Suggestion by @kamipo to turn |
b41b458
to
03d7ec6
Compare
Updated and rebased. |
@@ -50,7 +50,7 @@ def visit_TableDefinition(o) | |||
end | |||
|
|||
if supports_foreign_keys? | |||
statements.concat(o.foreign_keys.map { |to_table, options| foreign_key_in_create(o.name, to_table, options) }) | |||
statements.concat(o.foreign_keys.map { |fk| foreign_key_in_create(o.name, fk[0], fk[1]) }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to_table, options
-> fk[0], fk[1]
is reasonable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right; the original syntax works. I didn't realise that you could pass two parameters to the block like that when iterating over a nested array.
Reverted and rebased.
Previously if you used `t.foreign_key` twice within the same `create_table` block using the same `to_table`, all statements except the final one would fail silently. For example, the following code: def change create_table :flights do |t| t.integer :from_id, index: true, null: false t.integer :to_id, index: true, null: false t.foreign_key :airports, column: :from_id t.foreign_key :airports, column: :to_id end end Would only create one foreign key, on the column `from_id`. This commit allows multiple foreign keys to the same table to be created within one `create_table` block.
03d7ec6
to
aedde2a
Compare
Let t.foreign_key use the same `to_table` twice Conflicts: activerecord/CHANGELOG.md
@georgemillo thanks. I merged a slightly modified version with a single assertion in the test-case. This combines all assertions and will give much more context when something goes wrong. 84c1824#diff-110b6f2d17622b19682ec73cce8b015fR160 |
Let t.foreign_key use the same `to_table` twice
I just discovered this issue with migrations in Rails 5 beta 2. Say I want to create a table with multiple foreign keys pointing to the same table:
The problem is that this only creates the last foreign key (in this case the one on
to_id
) and ignores any previous foreign keys. From the source it's easy to see why:The hash keys are being re-used, so later definitions will overwrite previous ones.
This PR contains a simple fix, by turning
foreign_keys[table_name]
into an Array and allowing multiple definitions to be made for the sameto_table
.