Skip to content

Conversation

ghiculescu
Copy link
Member

Currently if you provide a non-boolean argument, change_column_null will treat it as truthy and make your column nullable. This might not be what you want. For example, I've noticed this happen a few times, where someone assumes that change_column_null and change_column_default have the same signature:

change_column_default(:posts, :state, from: nil, to: "draft")
change_column_null(:posts, :state, from: true, to: false)

Reading the migration you would expect that the default is now "draft" and the column doesn't accept nulls. But actually, the "null" argument is { from: true, to: false } which is truthy, so now the column accepts nulls. If you aren't paying close attention to the migration output you might miss this.

I think we can protect users here by having change_column_null require the 3rd argument to be true or false and raising an error otherwise. This PR implements that, for migrations created on Rails 7.1 onward.

@ghiculescu ghiculescu force-pushed the change-column-null-ux branch from df856f3 to eb9b076 Compare May 31, 2022 19:05
@ghiculescu ghiculescu force-pushed the change-column-null-ux branch from eb9b076 to b337075 Compare June 1, 2022 14:57
@ghiculescu
Copy link
Member Author

@fatkodima thanks for the great review ❤️

@ghiculescu ghiculescu force-pushed the change-column-null-ux branch from b337075 to 0fac0aa Compare June 1, 2022 17:31
Copy link
Member

@byroot byroot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems sensible, I'm 👍 . It just need a rebase. Let me know when it's down and I'll happily merge.

…ovided

Currently if you provide a non-boolean argument, `change_column_null` will treat it as truthy and make your column nullable. This might not be what you want. For example, I've noticed this happen a few times, where someone assumes that `change_column_null` and `change_column_default` work the same:

```ruby
change_column_default(:posts, :state, from: nil, to: "draft")
change_column_null(:posts, :state, from: true, to: false)
```

Reading the migration you would expect that the default is now "draft" and the column doesn't accept nulls. But actually, the "null" argument is `{ from: true, to: false }` which is truthy, so now the column accepts nulls. If you aren't paying close attention to the migration output you might miss this.

I think we can protect users here by having `change_column_null` require the 3rd argument to be `true` or `false` and raising an error otherwise. This PR implements that, for migrations created on Rails 7.1 onward.
@ghiculescu ghiculescu force-pushed the change-column-null-ux branch from 0fac0aa to 08dc02b Compare June 13, 2022 18:46
@ghiculescu ghiculescu requested a review from byroot June 13, 2022 18:47
@simi
Copy link
Contributor

simi commented Jun 13, 2022

LGTM

Btw. what about other methods handling DB NULL like add_column(..., null: 'random_string')? I have quickly tested add_column and it behaves the same (any truthy value => truth).

@ghiculescu
Copy link
Member Author

👍 that's a good call. We should do that too.

I can open a followup PR for that, unless @byroot (or anyone else) feels strongly about it being in the same PR.

@byroot
Copy link
Member

byroot commented Jun 13, 2022

like add_column(..., null: 'random_string')

In this case it's much more obvious that a boolean is expected.

The reason I'm 👍 on this particular PR is that it's indeed very easy to make that mistake, but it doesn't mean that we should check the type of every params everywhere.

@byroot byroot merged commit 2026d5b into rails:main Jun 13, 2022
@ghiculescu ghiculescu deleted the change-column-null-ux branch June 13, 2022 19:01
@simi
Copy link
Contributor

simi commented Jun 13, 2022

I can open a followup PR for that, unless @byroot (or anyone else) feels strongly about it being in the same PR.

Sorry for confusion, my intention wasn't to extend scope of this PR. I was just wondering if this is start of new pattern -> checking migration params. It seems random now. Something is checked, something not now. 🤷‍♂️

🤔 Also looking at the code, currently it is needed to do validation in each adapter on its own. That means adapters maintained
outside of AR will not benefit from this change. Currently it seems impossible to simply do this kind of check at one place. 😢

@byroot for the future, would it be welcomed to somehow wrap this into one shared entry for all adapters? I can try to prepare some initial PR to discuss. That way it would be much easier to bring similar changes.

@byroot
Copy link
Member

byroot commented Jun 13, 2022

If you find a way to avoid that duplication and to support third-party adapter, then yes it's welcome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants