-
Notifications
You must be signed in to change notification settings - Fork 21.7k
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
Require belongs_to
by default.
#18937
Conversation
63a04a1
to
66c389b
Compare
I wonder what to do with failing test.
This code fails now, since belongs_to relation is required by default. Should I change generated test for belongs_to to make it pass or should I remove this test since it is not valid with this change? |
|
||
def self.define_validations(model, reflection) | ||
if reflection.options.key?(:required) | ||
ActiveSupport::Deprecation.warn('`required` option for belongs_to relation is deprecated and replaced with `optional` option.') |
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.
Better info will be needed here. Any ideas?
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.
'required: true
is now the default for belongs_to and can be removed.' – don't even need to talk about optional here. What they wanted to do is now being done for them.
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.
What about when required: false
is specified explicitly? Maybe throw deprecation warning only for false
value?
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.
That was the old default, which means no client code will have that code, since it doesn’t make any sense.
On Feb 15, 2015, at 12:54 PM, Josef Šimánek notifications@github.com wrote:
In activerecord/lib/active_record/associations/builder/belongs_to.rb #18937 (comment):
@@ -110,5 +110,24 @@ def self.add_destroy_callbacks(model, reflection)
name = reflection.name
model.after_destroy lambda { |o| o.association(name).handle_dependency }
end
+
- def self.define_validations(model, reflection)
if reflection.options.key?(:required)
What about when required: false is specified explicitly? Maybe throw deprecation warning only for false value?ActiveSupport::Deprecation.warn('`required` option for belongs_to relation is deprecated and replaced with `optional` option.')
—
Reply to this email directly or view it on GitHub https://github.com/rails/rails/pull/18937/files#r24725940.
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.
OK, makes sense.
66c389b
to
b60ef6b
Compare
You can kill that test and replace it with a test that tests optional: true.
|
Should I add also this to generator? |
Nah, don’t think that’s necessary. Will be a very uncommon option to use, I think.
|
2494879
to
c134970
Compare
OK I think my work is almost done here. I'll add also CHANGELOG note soon. |
Awesome. Ping when ready to merge.
|
8d17afe
to
03ef4b4
Compare
I added CHANGELOG note, but it is a little fuzzy to me. Feel free to ping me with better one. |
This can by configure by `config.active_record.require_belongs_to` option | ||
or by `optional: true` option on relation. | ||
|
||
*Josef Šimánek* |
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.
Let's try with:
belongs_to
will now trigger a validation error by default if the association is not present. You can turn this off on a per-association basis with optional: true
. (Note this new default only applies to new Rails apps that will be generated with config.active_record.require_belongs_to = true
)
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.
Actually the final note is not true right now. config.active_record.require_belongs_to = true
is set directly in railtie, not in application config. Should I move it to new generated application.rb
and let it nil
for existing applications? In that case your note will be true.
Let's update the config option to be a bit clearer: |
This is also missing the config/initializers/active_record_belongs_to_required_by_default.rb file that's going to set the |
@dhh I mentioned that https://github.com/rails/rails/pull/18937/files#r24953865 already. |
Ah, we crossed streams. Didn't note that one. Yes, please do go ahead. Thanks! |
required = model.require_belongs_to | ||
else | ||
required = !reflection.options[:optional] | ||
end |
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'm finding the control flow here a little difficult to follow. Consider condensing the conditionals and using the :optional
option to determine whether to declare the presence validation:
# Disallow conflicting options
if reflection.options.key?(:required) && reflection.options.key?(:optional)
raise ArgumentError, "complain if we have conflicting options"
# Deprecate :required
elsif reflection.options.key?(:required)
reflection.options[:optional] = !reflection.options[:required]
ActiveSupport::Deprecation.warn "switch to `optional: #{reflection.options[:optional]}`"
# Set default :optional option
elsif !reflection.options.key?(:optional)
reflection.options[:optional] = !model.require_belongs_to
end
super
if !reflection.options[:optional]
model.validates_presence_of …
end
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.
Nice work @simi. Pardon the repeated remarks, looks like I missed concurrent feedback too. Thanks! |
Nevermind @jeremy. Thanks for review. I have just one more question. I made change where |
I bet it will be better as initializer after inspecting currently generated initializers. |
@jeremy @dhh I pushed new commit (I can squash later, just to highlight new code). This initializer is generated only when |
Since rails#18937 `belongs_to` associations receive a setting to determine if it should be or not treated as `required` by default. While the tests were still passing, it was not evident that the "default" behaviour for `required` could change in fuction of a setting, that is set by default for fresh Rails5 apps, but not for upgraded apps. This commit try to relate them to make it clear what is the behaviour expected when the setting is set as `true` or not set.
I feel this change was a bit of a mistake at the design level... validations and relations are different things, and now we get validations done when defining relations. I understand the "it's convenient" argument tho. |
@@ -956,6 +957,10 @@ end | |||
|
|||
If you set the `:validate` option to `true`, then associated objects will be validated whenever you save this object. By default, this is `false`: associated objects will not be validated when this object is saved. | |||
|
|||
##### `:optional` | |||
|
|||
If you set the `:optional` option to `true`, then associated object will be validated for presence. By default, this is `false`: associated objects will be validated for presence. |
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.
Typo: "then associated object will NOT be validated for presence"
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.
optional: By default, this is false: associated objects will be validated for presence.
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'm talking about the first part. Look more closely, the sentence says the same thing twice:
If you set the `:optional` option to `true`, then associated object
will be validated for presence. By default, this is `false`: associated objects
will be validated for presence.
I took the original sentence and just modified the alignement so it's visually clear they are the same.
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.
Ok, this was fixed in 803ef74
The referenced change for rails 5 is making the belongs_to relationships break validations for our models. This change makes them optional. rails/rails#18937
We are only testing for validation of the presence of the association ID, what if the given ID is invalid. And app behaviour is not to validate the existence of such association? |
…is required by default in rails 5. (rails/rails#18937)
…is required by default in rails 5. (rails/rails#18937) Revert all followers to old implementation
belongs_to will now trigger a validation error by default if the association is not present. You can turn this off on a per-association basis with optional: true. Also deprecate required option in favor of optional for belongs_to. (Pull Request) rails/rails#18937
belongs_to will now trigger a validation error by default if the association is not present. You can turn this off on a per-association basis with optional: true. Also deprecate required option in favor of optional for belongs_to. (Pull Request) rails/rails#18937
belongs_to will now trigger a validation error by default if the association is not present. You can turn this off on a per-association basis with optional: true. Also deprecate required option in favor of optional for belongs_to. (Pull Request) rails/rails#18937
`belongs_to` association have `required: true` by default rails#18937 onwards so we don't need it in the generator template. We still need the code for required in the command line generator as it adds `null: false` in the migration.
Deprecate
required
option in favor ofoptional
forbelongs_to
.closes #18233