-
Notifications
You must be signed in to change notification settings - Fork 21.8k
Allows you to check if a field has changed to a particular value #13131
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
Conversation
Related to #12763 |
@senny Did you link the right ticket? The one you linked to seems like a performance issue |
@gja I absolutely did not 😓 should be good now. |
I find that the example line of code It could mean that the name changed from "Ringo", or that it changed to "Ringo". |
Would you feel better about model.name_changed?(to: "Ringo") |
Personally not a fan of introducing a mini DSL inside a method, particularly
— On Mon, Dec 2, 2013 at 9:32 AM, Tejas Dinkar notifications@github.com
|
+1 @chancancode there is a gem that do something like your proposal |
the only thing is that it is a little long-winded as code |
@acapilleri Looks like that gem does fundamentally the same thing, but as an alias_method_chain (hmm, maybe I can do that as well). I'm not sure how to make the code shorter. Maybe by introducing an intermediate private method/class. |
What's the use case for @model.changed?(from: 'something')? I can see the to-case. |
@dhh I can see the value in specifying 'to', and both 'from and to' together. The latter could be used to check if an object has moved from one state to another, and potentially trigger some action / callbacks.
I suppose it would make sense to implement 'from' just to be complete / so that there are no surprises. |
Gotcha. I suppose that makes sense. I like this format. On Dec 9, 2013, at 9:42 AM, Tejas Dinkar notifications@github.com wrote:
|
Sorry I mean |
cool! @gja ping me when you update your Pr, because I have worked in the gem above. and could be great add also the |
@acapilleri I've update the PR, and I've implemented the API so it accepts lambda's for from and to. I'm guessing you mean something like this: I've used the case comparator operator (===) to check this equality (=== evaluates the block, and defaults to == for strings and numbers). I'm wondering if this is hacky. |
@gja I think using Whether we should support procs, Regexp etc is a different question. I'm leaning towards no, because like I said I'm not a big fan of these "mini-DSL" things inside a method.
|
assert !@model.name_changed?(from: "Pete") | ||
assert @model.name_changed?(to: -> name { name.start_with? "Ring" }) | ||
assert !@model.name_changed?(to: -> name { name.end_with? "Ring" }) | ||
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.
Please use assert_not
Considering this module is most used in active record, where sometimes tracking the changes can generate a bunch of code, could be nice, for example, use a method like: |
Personally, I think using a proc in these scenarios is not very readable: if user.role_changed?(to: -> (role) { ["admin", "super_admin"].incude?(role) })
# ...
end
# ...compared to...
if user.role_changed? && (user.role == "admin" || user.role == "super_admin")
# ...
end So speaking for myself, I'd probably never use a proc like this, and I'd prefer not having to read code that does that. However, using It also could in theory cause problems for certain Ruby types that overrides So, in summary, I personally don't prefer the |
I could personally go either way wrt to accepting lambdas (but lean towards @chancancode's arguments). I suppose we could try a minimal approach, and start by only accepting values in. If a lot of people use this and want lambdas, then we could include that later. This is my first major pull request to rails. How do these differences in opinion usually get resolved? |
IMHO if user.role_changed?(to: -> (role) { ["admin", "super_admin"].incude?(role) }) is expressive code than user 3 boolean relations if user.role_changed?(from: -> (role) { ["admin", "super_admin"].incude?(role) }) Also in many cases Regarding |
I don't think we need to support procs/lambdas here, having the basic functionality will solve most of the cases. |
@acapilleri @chancancode @carlosantoniodasilva It looks like most people are against lambdas. @acapilleri Would your usecase be solved by accepting an enumerable, to check inclusion? That actually could read well user.role_changed?(from: %w(admin super_admin)) |
@gja 👎 that would make it impossible to make this work with pgsql Array and JSON types, for example. I think if user.role_changed? && ["admin", "super_admin"].incude?(user.role_was)
# ...
end |
@gja use an |
def attribute_changed?(attr, options = {}) | ||
result = changed_attributes.include?(attr) | ||
result &&= options[:to] == __send__(attr) if options.key?(:to) | ||
result &&= options[:from] == changes[attr].first if options.key?(:from) |
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 probably shouldn't not use changes
here, because it makes the code very difficult to follow, and unnecessarily inefficient :(
You see, changes
internally calls attribute_change
, which calls attribute_changed?
again (!)
Seeing that changed_attributes
already give you the original value, you should probably use that instead. :)
Hi @gja, when you addressed the comment above, can you also do these? Thanks 💛
|
model.name_changed?(from: "Pete", to: "Ringo")
@chancancode Did you get a chance to look at the lastest commit? |
Allows you to check if a field has changed to a particular value
@gja thanks 😁 |
👍 Thank you, this looks great. |
I'll add documentation if people are interested in this change
model.name_changed?("Ringo")
model.name_changed?("John" => "Ringo")