Skip to content
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

Add dirty methods for store accessors #19333

Merged
merged 2 commits into from Mar 31, 2019
Merged

Add dirty methods for store accessors #19333

merged 2 commits into from Mar 31, 2019

Conversation

@palkan
Copy link
Contributor

@palkan palkan commented Mar 14, 2015

Example:

class User < AR:Base
  store_accessor :settings, :color
end

u = User.new
u.color_changed? #=> false

u.color = 'red-n-white'
# Or
u.settings['color'] = 'red-n-white'

u.color_changed? #=> true
u.color_was #=> nil
u.color_change #=> [nil, 'red-n-white']

Also, force Model.stored_attributes[:store] array to contain string keys.

@palkan palkan force-pushed the dirty-store branch 2 times, most recently from 29d7752 to 942fe13 Jun 18, 2015
@palkan
Copy link
Contributor Author

@palkan palkan commented Jun 18, 2015

@rafaelfranca @sgrif Any feedback on that?

@sgrif
Copy link
Contributor

@sgrif sgrif commented Jun 18, 2015

I think that this falls into the bucket of "we should just promote store accessors to proper attributes".

@palkan
Copy link
Contributor Author

@palkan palkan commented Jun 18, 2015

@sgrif Interesting. Is anyone struggling with that?

@palkan
Copy link
Contributor Author

@palkan palkan commented Apr 12, 2017

Just found myself struggling with the absence of accessors dirty methods. Maybe, we should revamp this PR? It's pretty simple but useful change, IMO.

/cc @rafaelfranca @matthewd

@palkan
Copy link
Contributor Author

@palkan palkan commented Mar 20, 2019

Years have passed. I'm still missing this 😢

Maybe, Rails 6 is a good place for this feature? @kaspth WDYT?

activerecord/test/cases/store_test.rb Outdated Show resolved Hide resolved
define_method("#{key}_changed?") do
return false unless attribute_changed?(store_attribute)
prev_store, new_store = changes[store_attribute]
prev_store.try(:[], key) != new_store.try(:[], key)
Copy link
Member

@kaspth kaspth Mar 20, 2019

Let's go with &.dig(key) instead of the try.

activerecord/test/cases/adapters/postgresql/hstore_test.rb Outdated Show resolved Hide resolved
activerecord/test/cases/store_test.rb Outdated Show resolved Hide resolved
activerecord/lib/active_record/store.rb Outdated Show resolved Hide resolved
# u.color_changed? # => true
# u.color_was # => 'black'
# u.color_change # => ['black', 'red']
#
# # Add additional accessors to an existing store through store_accessor
# class SuperUser < User
# store_accessor :settings, :privileges, :servants
Copy link
Member

@kaspth kaspth Mar 20, 2019

These'll also get change tracking too, right?

Copy link
Contributor Author

@palkan palkan Mar 25, 2019

Could you please explain, what did you mean here?

Copy link
Member

@kaspth kaspth Mar 31, 2019

It's basically what you demonstrate in your PR description. I'm just asking if store_accessor :color also adds color_changed? etc. or if we missed it and only store :settings, accessors: %i( color ) would get it.

@palkan palkan force-pushed the dirty-store branch 2 times, most recently from 65698c8 to 619c038 Mar 25, 2019
@palkan
Copy link
Contributor Author

@palkan palkan commented Mar 25, 2019

@kaspth Hey! Thanks for the feedback!

I've addressed all the comments and actualized the PR by adding saved changes helpers as well.

@kaspth kaspth merged commit ba4e74e into rails:master Mar 31, 2019
3 checks passed
@LucasArruda
Copy link

@LucasArruda LucasArruda commented Aug 16, 2019

This feature proves you should never ever give up! 👍

@wbcasey
Copy link

@wbcasey wbcasey commented Jun 27, 2020

What's the easiest way to backport this to Rails 4.2?

@palkan
Copy link
Contributor Author

@palkan palkan commented Jun 29, 2020

@wbcasey You can patch ActiveRecord::Store::ClassMethods#store_accessor method to add additional methods. Smth like:

ActiveSupport.on_load(:active_record) do
  ActiveRecord::Store::ClassMethods.prepend(Module.new do
    def store_accessor(store_name, *keys)
      super
      keys = keys.flatten
      _store_accessors_module.module_eval do
          keys.each do |key|
            define_method("#{key}_changed?") do
              return false unless attribute_changed?(store_name)
              prev_store, new_store = changes[store_name]
              prev_store&.dig(key) != new_store&.dig(key)
            end
          end
          # ...
       end
    end
  end)
end

@LucasArruda
Copy link

@LucasArruda LucasArruda commented Jun 29, 2020

@wbcasey defining those methods there?

@wbcasey
Copy link

@wbcasey wbcasey commented Jun 29, 2020

@LucasArruda basically back-porting the "dirty" functionality. I tried just bringing it in, but some of the API surface has changed between 4.2 and 6.x

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

Successfully merging this pull request may close these issues.

None yet

8 participants