model name prefix is not always unique
khiav223577 opened this issue · 10 comments
The document here says:
Redis::Objects automatically creates keys that are unique to each object, in the format:
model_name:id:field_name
But if two models in different namespace have same name. The generated key will be the same.
For example:
class Group < ActiveRecord::Base
include Redis::Objects
counter :test_counter
end
class XXX::Group < ActiveRecord::Base
include Redis::Objects
counter :test_counter
end
Group.first.test_counter.key
# => "group:1:test_counter"
XXX::Group.first.test_counter.key
# => "group:1:test_counter"
Nested class names are a problem because I stole the original code from Sinatra, and unfortunately I didn't notice that it cropped the class down past the final ::
. Sorry. I am open to a new option something like full_prefix: true
but unfortunately we can't change the code since that would be backwards incompatible.
I finally have an idea. If we bumped the version to 2.0.0
, we could issue a warning message in the model_prefix
method if we found an ::
that we are now prefixing the full method name. And/or we could provide a global setting called long_namespacing
where if you said it to false
it would do the old shortened version. CC @tmsrjs
@nateware I think you might want to provide this as an option at the object level as well so that if you were using redis objects for a namespaced class upgrading wouldnt break existing code. Meaning you can turn on new behavior and get benefits of namespaced keys without breaking currently functioning code in your app.
@nateware class level makes sense. Although it's probably an edge case this still wouldn't support existing namespaced classes with a mixture of new and old functionality. Say you add redis type after upgrading and want new definition to use namespaced keys even though existing ones wouldn't without migrating. Maybe we don't care about this but thought it might be worth mentioning. If we did care than it might make sense to add option at the instance level when defining new redis types on class.
Like @khiav223577 said, developer barely cannot notice that models in different namespace could have same name. We set redis_prefix in every included class, If the new one does not know to set this, there will be problems. Still think that using model_name by default is not very reasonable.
By the way, why redis_prefix should use sub and gsub?
def redis_prefix(klass = self) #:nodoc:
@redis_prefix ||= klass.name.to_s.
sub(%r{(.*::)}, '').
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
gsub(/([a-z\d])([A-Z])/,'\1_\2').
downcase
end
Can we just change it as follow:
def redis_prefix(klass = self) #:nodoc:
@redis_prefix ||= klass.name.to_s.
gsub(/::/, '_').
downcase
end
Update on the design to fix this longstanding issue. The new code for redis_prefix
looks like so:
def modern_redis_prefix(klass = self) #:nodoc:
klass.name.to_s.
gsub(/::/, '__'). # Nested::Class => Nested__Class
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). # ClassName => Class_Name
gsub(/([a-z\d])([A-Z])/,'\1_\2'). # className => class_Name
downcase
end
The reason I chose __
as a substitute for ::
was to ensure these don't conflict:
class Group::PlayerType # group__player_type
class GroupPlayer::Type # group_player__type
To cause the legacy key naming behavior, there is a new flag redis_legacy_naming
:
class MyClass
include Redis::Objects
self.redis_legacy_naming = true
A warning will be emitted if redis-objects
detects that your class name will change.
This is being developed in the long_namespace
branch for those interested in following along.
This has been fixed in 2.0.0.alpha
and pushed to rubygems
Also fixed in 2.0.0.beta
which I just pushed to rubygems