Basic support for adding and removing foreign keys#15606
Basic support for adding and removing foreign keys#15606rafaelfranca merged 18 commits intorails:masterfrom
Conversation
|
Thank you. One thing to make work is the automatic test schema could you check if it is working now? I know it doesn't with foreigner |
|
I have not checked the patch but something in the example code caught my attention. Foreign keys have
What about two explicit flags Coincidentally I have heavily used |
|
@fxn the current implementation does not allow for def dependency_sql(dependency)
case dependency
when :nullify then "ON DELETE SET NULL"
when :delete then "ON DELETE CASCADE"
when :restrict then "ON DELETE RESTRICT"
else ""
end
endA simple boolean is not enough. This also varies per adapter. PostgreSQL for example has a default of |
|
Ah, I see didn't remember that. Why isn't |
|
@fxn because I did not implement it yet 😅 |
|
Haha :). So yes, at the database schema level |
|
@fxn agreed. Will update accordingly. |
|
I might as well chime in!
change_table :widgets do |t|
t.foreign_key :factories
end
# widgets.factory_id now has a foreign key and an index.
change_table :widgets do |t|
t.remove_foreign_key :factories
end
# widgets still has an index on factory_id
Anyways, those are the things I learned over the last 5 years of trying to keep |
|
@matthuhiggins thanks so much for sharing your insight. Will investigate further to provide a sound starting point. I mostly agree with your points, I'm skeptical about the fk naming though. We had many issues because identifiers that got too long. I'd like to stick to a short naming when possible. Any thoughts on that? |
|
Regarding FKs protect you from orphan records in the common case, but also allow you to define what to do when something happens to the parent record. In the use case I mentioned before, I need to issue dozens of statements like this: UPDATE foos SET id = id + delta;and I believe that if we add support for FKs then we need to adapt to whatever FKs mean to database writers. |
|
Your current naming is completely fine too. Yes, I am aware of the naming limits, in particular with postgres. It is less likely to occur with foreign keys, since it is on only one column rather than multiple. Your choice is completely fine (hey now, it was my choice too). There is also Great work btw. I hope that some form of this makes it in. |
|
@fxn That is completely reasonable. I was stating where I personally drew the line, and therefore did not support. Similarly, I never supported composite foreign keys. Per your philosophy, should composite foreign keys be supported? @senny Make sure that this issue does not exist with your new implementation: matthuhiggins/foreigner#110 |
|
@matthuhiggins thanks for the issue reference. I think this is the behavior @rafaelfranca was talking about. As we now have automatic schema maintenance for test runs, this is even more important. I haven't settled on a solution yet but will investigate dropping the database and not the tables. |
|
@matthuhiggins Oh absolutely, regading your feedback. Just to be clear I was also talking from the point of view of a team member thinking about a new feature in Rails, without implying anything about your choices in foreigner, since that is your baby and I totally respect your choices there, couldn't be otherwise :). Regarding composite FKs, I have never used them. In principle I'd say yes from the point of view of Active Record. If there's support for FKs I'd expect support for multiple columns. But then it also depends on practical matters, does it complicate the interface, is it worthwhile? So I'd say yes unless there are practical trade-offs that suggest not to support it. In the case of |
|
we already use foreigner in our code. is this patch fully compatible with existing code that uses foreigner's syntax? |
why not? remove_column is reversible in rails 4 provided it was defined with the params that add_column would usually require |
There was a problem hiding this comment.
foreigner accepts arbitrary options like add_foreign_key(:comments, :posts, options: 'ON UPDATE DEFERRED'). WDYT of supporting that?
There was a problem hiding this comment.
I will probably add something of that sort but for now, I'd like to get the basic functionality working and merged.
|
And of course, much ❤️ for proposing this to core Rails. I always thought that "getting started quickly" and "convention over configuration" doesn't mean "throw basic sane db design out the window". Not having db-level foreign key constraints and only relying on validations/assocs just means a world of hurt when you have to deal with production maintenance, changing application code, data migrations, etc. So IMO this is a much needed patch and should also have docs that encourage it's use to the same tune as indexes and null constraints. |
|
Also, one thing that bit me with |
|
@fxn Why do you think we need to provide a complete solution for FK's? When I look at other methods from the migration DSL it becomes obvious that we only support a small subset of what would be possible. You can always drop down to I'm not opposed to build to a more complete solution but I think we should be shipping this as soon as we hit 80 / 20. |
|
@senny note that my answer had some ifs :). |
|
@egilburg there is basic compatibility between the current implementation and foreigner. The name of the options might vary (currently we have 1.) remove foreigner I will look into the renaming stuff. I know we do this for indexes. |
|
One thing possibly worth considering: composite key foreign keys. |
The name of the foreign key is not relevant from a users perspective. Using random names resolves the urge to rename the foreign key when the respective table or column is renamed.
Basic support for adding and removing foreign keys
|
Really awesome work as usual 👏 👏 👏 👏 |
|
<3 <3 <3 Thanks a lot, @senny! |
|
Good work @senny, tks! 👍 |
|
Nicely done! 👍 |
|
thanks guys ❤️ |
|
Nice, really useful. Thanks from Switzerland @senny! |
|
Well done, love this. If anything can we make sure all the work by @matthuhiggins is being incorporated. I use Foreigner in all apps, would be best to have a smooth transition between the two. |
|
@tilsammans as described above you can transition to this. There will be small differences in the API and especially in the naming of foreign keys. A lot of this PR is based on the work of @matthuhiggins and his work on foreigner. Hopefully we can improve this first draft down the line. ❤️ |
|
Thanks for getting this into rails Yves! <3 |
|
Awesome work here! ❤️ |
|
Great stuff. I gladly relinquish my technical debt to Rails! |
|
Finally! Thank you. ❤️ |
We had this as a GSoC idea but there was no accepted student to work on it. Because I was really looking forward to see this in
rails/railsI made a first draft.This patch adds basic support for adding and removing foreign keys using the migration DSL:
Removing a foreign key works mostly the same:
Foreign keys are dumped after the indexes to
schema.rb. The optionsnameandcolumnare always dumped.dependentonly when set.add_foreign_keyis reversible,remove_foreign_keyis not.There is a
connection#supports_foreign_keys?method to determine wether the adapter does support the API.TODO:
add-/remove_foreign_keyshould be no-op whensupports_foreign_keys?isfalseon_deleteand introduceon_updateFuture Work (not this PR):
This patch was hugely inspired by
foreigner. Credits to @matthuhiggins ❤️