Allow prefix/suffix options for store accessors #29373
Conversation
Thanks for the pull request, and welcome! The Rails team is excited to review your changes, and you should hear from @rafaelfranca (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. This repository is being automatically checked for code quality issues using Code Climate. You can see results for this analysis in the PR status below. Newly introduced issues should be fixed before a Pull Request is considered ready to review. Please see the contribution instructions for more information. |
Still relevant in |
def store_accessor(store_attribute, *keys) | ||
keys = keys.flatten | ||
def store_accessor(store_attribute, *args) | ||
options = args.last.is_a?(Hash) ? args.pop : {} |
gmcgibbon
May 21, 2018
Member
I think you can do extract_options!
here instead.
I think you can do extract_options!
here instead.
# # Optionally specify prefix/suffix to accessor with _prefix/_suffix option | ||
# class User | ||
# store :settings, accessors: [ :two_factor_auth ], coder: JSON, _prefix: true | ||
# store_accessor :settings, :secret_question, _prefix: 'config' |
gmcgibbon
May 21, 2018
Member
Should it be _prefix
or prefix
like in active support's delegate
? I guess enum
have underscored options but I'm not sure which is preferred.
Should it be _prefix
or prefix
like in active support's delegate
? I guess enum
have underscored options but I'm not sure which is preferred.
rafaelfranca
May 22, 2018
Member
Without underscore, is the preffered way.
Without underscore, is the preffered way.
# class User | ||
# store :settings, accessors: [ :two_factor_auth ], coder: JSON, _prefix: true | ||
# store_accessor :settings, :secret_question, _prefix: 'config' | ||
# store_accessor :settings, :login_retry, _suffix: 'setting' |
gmcgibbon
May 21, 2018
Member
Should the examples be using symbols instead of strings for _prefix
and _suffix
values?
Should the examples be using symbols instead of strings for _prefix
and _suffix
values?
Thanks for the comments @gmcgibbon. Looks like another similar PR #32306 was created and merged before they had noticed this PR... @rafaelfranca (or someone), if you think it's worth adding suffix option or this PR can improve something related, I would be happy to contribute! |
Ah, thanks for pointing that out @untidy-hair. I'd say you're good to rebase and add the suffix option but if you want to wait for a core member's approval that's cool too |
well, i'm not waiting for an approval but i just want to make sure they recognize this PR this time haha :P |
I'm going to work on this this weekend :) |
Rebased and updated per comments :) @gmcgibbon, @rafaelfranca please review again. Thanks! |
|
Thanks for the review @gmcgibbon! @rafaelfranca, can we merge this? |
@@ -123,7 +120,21 @@ def store_accessor(store_attribute, *keys, prefix: nil) | |||
|
|||
def _store_accessors_module # :nodoc: | |||
@_store_accessors_module ||= begin | |||
mod = Module.new | |||
mod = Module.new do | |||
def self.stored_accessor_key(store_attribute, key, options) |
kamipo
Jun 1, 2018
•
Member
Why do we define the helper method in each _store_accessors_module
s?
Why do we define the helper method in each _store_accessors_module
s?
untidy-hair
Jun 1, 2018
Author
Contributor
@kamipo, thanks for the review! The definition is there so that we can call the chunk of code in _store_accessors_module context, but it's true that each model that calls store/store_accessor defines the helper method inside the _store_accessors_module. Maybe I should just move that part of code directly into inside the module_eval block, unless you have any better suggestion. If you do, let me know :)
@kamipo, thanks for the review! The definition is there so that we can call the chunk of code in _store_accessors_module context, but it's true that each model that calls store/store_accessor defines the helper method inside the _store_accessors_module. Maybe I should just move that part of code directly into inside the module_eval block, unless you have any better suggestion. If you do, let me know :)
@kamipo updated. please review again. Thanks! |
# end | ||
# | ||
# The stored attribute names can be retrieved using {.stored_attributes}[rdoc-ref:rdoc-ref:ClassMethods#stored_attributes]. | ||
# | ||
# User.stored_attributes[:settings] # [:color, :homepage] | ||
# User.stored_attributes[:settings] # [:color, :homepage, :two_factor_auth, :login_retry, :secret_question] |
kamipo
Jun 9, 2018
Member
Looks like that isn't correct appeared a subclass' accessor :secret_question
.
Looks like that isn't correct appeared a subclass' accessor :secret_question
.
@@ -86,29 +91,32 @@ class << self | |||
module ClassMethods | |||
def store(store_attribute, options = {}) | |||
serialize store_attribute, IndifferentCoder.new(store_attribute, options[:coder]) | |||
store_accessor(store_attribute, options[:accessors], prefix: options[:prefix]) if options.has_key? :accessors | |||
store_accessor(store_attribute, options.delete(:accessors), options) if options.has_key? :accessors |
kamipo
Jun 9, 2018
Member
store_accessor(store_attribute, options[:accessors], options.slice(:prefix, :suffix)) if options.has_key? :accessors`
store_accessor(store_attribute, options[:accessors], options.slice(:prefix, :suffix)) if options.has_key? :accessors`
else | ||
"" | ||
end | ||
def store_accessor(store_attribute, *args) |
kamipo
Jun 9, 2018
Member
def store_accessor(store_attribute, *keys, prefix: nil, suffix: nil)
def store_accessor(store_attribute, *keys, prefix: nil, suffix: nil)
|
||
_store_accessors_module.module_eval do | ||
keys.each do |key| | ||
define_method("#{accessor_prefix}#{key}=") do |value| | ||
prefix = if options[:prefix] == true |
kamipo
Jun 9, 2018
Member
The prefix/suffix is just enough calculated once, there is no reason to do for each keys.
The prefix/suffix is just enough calculated once, there is no reason to do for each keys.
@kamipo thanks for the comments. updated. |
Allow prefix/suffix options for store accessors
Thanks! |
Summary
####Background:
There was a situation where association
has_many :dependencies
existedwhereas we needed the same key "dependencies" (the value is array of dependency's names) as a part of "settings" JSON, too, so that the JSON can be consumed as it is from some other stuff.
We needed SampleModel#dependencies to return the association dependencies (and thus we wanted to add a method like setting_dependencies for JSON dependencies),
but the default behavior of SampleModel#dependencies above is to return JSON dependencies.
####Workarounds:
=> Didn't quite work well.
has_many :my_dependencies, class: Dependency
and havedef dependencies; my_dependencies; end
to override=> Too much carefulness is necessary to cover other methods that has_many generates so I avoided this.
store (or store_accessor)
for JSON dependencies, and adddef setting_dependencies; settings[:dependencies]; end
(and setter also).=> This was the most viable option. But dependencies does not show up in SampleModel.stored_attributes (however you can add it).
But in the end, among stored accessors, only dependencies had
setting_
prefix.To be consistent and clearer, I ended up with adding
setting_
for other stored accessors, too, in the similar way as No3 above. (setting_color/setting_dependencies for SampleModel above.)This PR allows this prefix as an option out of the box.
The above was just one case but I think there will be some other cases, too, where prefix/suffix option is convenient and useful.
(Btw I referenced enum prefix for the implementation.)
Lastly, thank you for the great work, Rails team!