-
Notifications
You must be signed in to change notification settings - Fork 21.8k
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
Validate multiple contexts on valid?
and invalid?
at once
#21069
Validate multiple contexts on valid?
and invalid?
at once
#21069
Conversation
Example: ```ruby class Person include ActiveModel::Validations attr_reader :name, :title validates_presence_of :name, on: :create validates_presence_of :title, on: :update end person = Person.new person.valid?([:create, :update]) # => true person.errors.messages # => {:name=>["can't be blank"], :title=>["can't be blank"]} ```
d794ed4
to
86e3b04
Compare
Hi @dmitry. I couldn't realise the real world example. Can you give a code example to show as a developer in which case I need to check the validity of an object in multiple contexts. |
@meinac hey, thank you for the critics! For example, imagine you have a multiple steps before you could create an order. You would like to add more and more validations on each steps, so each step will validate all the previous step validations + current one. Another example, actually what I've got recently (but we are still on rails 3.2.x, hopefully will update soon or later), when you want to validate model for almost everything, except presence of the user, in that case when user isn't logged in yet or not created his profile, which will be created through the nested attributes. I can think of other possible cases, which can be solved a other way around, but in some cases it's really better to have this feature to make everything easier. |
👍 This would enable to remove conditional validations. Much needed feature. |
Through it's 5x slower, it's really helpful feature. require 'benchmark'
a = [:a, :b]
b = :b
n = 10000000
Benchmark.bm do |x|
x.report { n.times do !(Array(a) & Array(b)).empty? end }
x.report { n.times do Array(a).include?(b) end }
end
|
I would be glad to rebase this PR if anyone from the core agrees to merge it into the master. |
How much does I don't think this change is worth it over just doing |
@kaspth I've answered on the both questions above :) With Slowdown is 5x times, but can be improved a little bit with |
Duh, sorry! 😄
Is that for |
Not x.report { n.times do !(Array(a) & Array(b)).empty? end }
x.report { n.times do Array(a).include?(b) end } I believe it will slowdown PS. Looks like it's much easier to close this PR, because such cases might be moved to the |
I don't think this slowdown will change anything. This feature is something that I wanted to implement some times so I think it is worth. |
end | ||
|
||
person = Person.new | ||
person.valid?([:create, :update]) # => 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.
How many changes would be necessary to make person.valid?(:create, :update)
work?
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.
Not many changes should be made, but the interface of the valid?(context)
should be changed to valid?(*context)
in activemodel/activerecord implementations (and everywhere where is valid?
is used should be changed as well, like save
, invalid?
and so on). It can brake some gems.
In the beginning I went by this path, but then after changing a lot of places in the code, I found that using an array actually can fit better to whole conception, because it makes sense to pass an array instead of passing an array through a splat; passing a simple array without splat will look more clean in many cases.
…xts-at-once Validate multiple contexts on `valid?` and `invalid?` at once
It broke Active Record tests. I revert it. Could you take a look on these failures and open a new PR? |
@rafaelfranca fixed at #21535 PS. Broken because some code left when I tried to make it to work as splat params. |
- Followup of rails#21069. - [ci skip]
…e contexts.` Though the validation have supported multiple context since rails#21069, its callbacks don't support multiple context currently. So I regarded this as the bug and fixed. Example: ```ruby class Dog include ActiveModel::Validations include ActiveModel::Validations::Callbacks attr_accessor :history def initialize @history = [] end before_validation :set_before_validation_on_a, on: :a before_validation :set_before_validation_on_b, on: :b after_validation :set_after_validation_on_a, on: :a after_validation :set_after_validation_on_b, on: :b def set_before_validation_on_a; history << "before_validation on a"; end def set_before_validation_on_b; history << "before_validation on b"; end def set_after_validation_on_a; history << "after_validation on a" ; end def set_after_validation_on_b; history << "after_validation on b" ; end end ``` Before: ``` d = Dog.new d.valid?([:a, :b]) d.history # [] ``` After: ``` d = Dog.new d.valid?([:a, :b]) d.history # ["before_validation on a", "before_validation on b", "after_validation on a", "after_validation on b"] ```
Lets say we have cascade of validations, when we should check more and more validations, after each step. As an example:
precreate
context should check everything in a create, but less 2 attributes (real word example).Currently it's only possible to check validations one by one. This patch provides possibility to do all the checks at once.
Example: