adzap / active_enum Goto Github PK
View Code? Open in Web Editor NEWDefine enum classes in Rails and use them to enumerate ActiveRecord attributes, with I18n support
Home Page: http://github.com/adzap/active_enum
License: MIT License
Define enum classes in Rails and use them to enumerate ActiveRecord attributes, with I18n support
Home Page: http://github.com/adzap/active_enum
License: MIT License
Hi! Your approach looks very promising. There is one feature that might be interesting, but I wasn't able to find it in the README and a glimpse into the code did not reveal it either: does ActiveEnum support String keys (including a String column in the DB)?
Background: https://api.rubyonrails.org/v7.0/classes/ActiveRecord/Enum.html
Finally it's also possible to use a string column to persist the enumerated value. Note that this will likely lead to slower database queries:
class Conversation < ActiveRecord::Base
enum :status, active: "active", archived: "archived"
end
See https://github.com/plataformatec/simple_form/issues/issue/156
The default_input_type
method breaks.
Thanks for this gem. It's a great help in my current project. But I would like to answer @adzap in issue #21 in hopes of restarting the idea. The use case is readability of the underlying database. If I set up an enum for genders, the states or provinces of a country, race/ethnic groups, etc., and the database is used by non-Rails applications, it's much cleaner if the value e.g. New York corresponds to an id that's an understandable abbreviation e.g. 'ny' rather than an integer. This is best practice in database design. I hope you'll consider allowing string values in the next version. Your proposal will work fine: Enum.id(name) and Enum.name(id) . You could retain the bracket notation and raise an exception if the user tries to use it on an enum that has string ids. If I have time I'll take a crack at it in a fork.
According to this code, ActiveEnum''s enumerate attribute isn't translated if id
isn't a Fixnum
. For example I can use a String
for id
. Then I get row[0]
(untranslated) but not row[1]
(translated);
# lib/active_enum/base.rb#57
# ActiveEnum::Base
def get(index)
if index.is_a?(Fixnum)
row = store.get_by_id(index)
row[1] if row
else
row = store.get_by_name(index)
row[0] if row
end
end
# lib/active_enum/storage/i18n_store.rb
# ActiveEnum::Storage::I18n
def get_by_name(name)
row = _values.rassoc(name.to_s)
[ row[0], translate(row[1]), row[2] ].compact if row
end
Why? Thanks.
Hello,
I'm trying to update an application using active_enum to rails 4.0
Currently the active_enum gem has a dependency on activesupport ~> 3.0
that prevents its from using activesupport 4.0
Other than that, it looks like the gem is compatible with rails 4.0
I suggest to provide in the gem rspec matcher for inclusion validator. What do you think? The code is below:
RSpec::Matchers.define :validate_inclusion_enum do |enum_class|
chain :for do |attribute|
@attribute = attribute.to_sym
end
match do |model|
validators = model._validators[@attribute]
inclusion_validator = validators.detect {|v| v.is_a? ActiveModel::Validations::InclusionValidator }
inclusion_validator && inclusion_validator.options[:in] == enum_class
end
end
I'm getting a NoMethodError for enumerate
in my ActiveRecord models. I followed the site instructions exactly, can interact with Enum classes in Console.
Running Rails 3.0.9 and MRI 1.9.2.
It would be great to have ability to get id of enum or name by method. For example, say we have this enum:
class UserRole < ActiveEnum::Base
value name: :user
value name: :admin
value name: :super_admin
end
I want to get user
role with such code: UserRole.user # => "User"
where "User" here is a translation. And its id: UserRole.user_id # => 1
. When I fetch the stuff with method te code is more reliable - it's like having constants for each enum, that's why we want to have this functionality in the gem.
In our project we have implemented this with the following module:
module BaseActiveEnum
extend ActiveSupport::Concern
included do
class << self
alias_method :names, :to_select
end
private
def self.origin_names_with_ids
@origin_names_with_ids ||= has_translation? ? translation.keys.zip(1..names.size) : names
end
def self.i18n_key
@i18n_key ||= self.name.underscore
end
def self.has_translation?
translation.is_a?(Hash)
end
def self.translation
@translation ||= I18n.t(i18n_key, scope: :active_enum)
end
public
origin_names_with_ids.each do |pair|
name, id = pair
name = name.to_s.gsub(/\s+/, '').underscore
define_singleton_method(name) { self[id] }
define_singleton_method("#{name}_id") { self[name] }
end
end
end
Then including it to the enum: UserRole.include(BaseActiveEnum)
gives us the requested functionality. I want to share this with you and ask is it reasonable to push this to the gem or not. What do you think? If you reject my proposal anyway the solution may be useful for somebody. But this gem is the most reliable and simplest which I've used as enum, and I believe that this functionality will make it much better.
It'd be great if there was an ability to call 'to_select' on a list of enums as opposed to the class method call which returns all enums in a select list.
Lets say you have an enum class
class Access < ActiveEnum::Base
value id: 1, name: 'Read'
value id: 2, name: 'Write'
value id: 3, name: 'Delete'
value id: 4, name: 'Other'
end
=> Access.to_select
Which returns
=> [ ["Read", 1],["Write", 2], ["Delete", 3], ["Other", 4] ]
Is there an ability to specify certain values in an array and return the to_select for just those enums?
=> Access[1,3].to_select
To return
=> [ ["Read", 1], ["Delete", 2] ]
With Rails 6.1, the following code in initializers/active_enum.rb
:
# Extend classes to add enumerate method
config.extend_classes = [ ActiveRecord::Base ]
throws this error:
/Users/thornett/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/activerecord-6.1.2.1/lib/active_record/dynamic_matchers.rb:22:in `method_missing': undefined method `class_inheritable_accessor' for ActiveRecord::Base:Class
Did you mean? class_variables (NoMethodError)
when the app attempts to load.
Looks like something may have changed internally in Rails that active_enum is trying to manipulate on startup.
Seems to work after I put the following line in an initializer:
require 'active_enum/acts_as_enum'
I get this warning when using this plugin with rails 3.1
DEPRECATION WARNING: class_inheritable_attribute is deprecated, please use class_attribute method instead. Notice their behavior are slightly different, so refer to class_attribute documentation first. (called from block in <top (required)> at /Users/[...]/config/initializers/active_enum.rb:4
Where the row causing the error is
config.extend_classes = [ ActiveRecord::Base ]
My configuration in full looks like
require 'active_enum/form_helpers/simple_form'
ActiveEnum.setup do |config|
config.extend_classes = [ ActiveRecord::Base ]
end
First off thanks for the great lib:exclamation:
Second, call me nostalgic, but being able to access the enums as a constant would be a nice addition. For example:
class State < ActiveEnum::Base
value 1 => "Available"
value 2 => "In Progress"
# ...
end
State::AVAILABLE
State::IN_PROGRESS
It's sorta almost there now with:
State["IN_PROGRESS"]
Let me know what you think. If so I'll submit a pull request.
Hi,
I get an error from formtastic. What am I doing wrong?
ActionView::Template::Error (Unable to find input class for enum): 1: <%= semantic_form_for @filter_rule do |f| %> 2: <%= f.inputs %> 3: <%= f.actions %> 4: <% end %> app/views/filter_rules/_form.html.erb:2:in `block in _app_views_filter_rules__form_html_erb___1761557587620786887_70204566903900' app/views/filter_rules/_form.html.erb:1:in `_app_views_filter_rules__form_html_erb___1761557587620786887_70204566903900' app/views/filter_rules/new.html.erb:5:in `_app_views_filter_rules_new_html_erb__965338666889571281_70204566763960' app/controllers/filter_rules_controller.rb:29:in `new'
I've verified that the form helper is included:
[ruben@rauscher mailtables]$ tail /Users/ruben/.rvm/gems/ruby-1.9.3-p392/gems/active_enum-0.9.12/lib/active_enum/form_helpers/formtastic2.rb super end end end end puts "foooooooooo" Formtastic::FormBuilder.send :include, ActiveEnum::FormHelpers::Formtastic2 p Formtastic::FormBuilder.included_modules [ruben@rauscher mailtables]$ be rails server => Booting WEBrick => Rails 3.2.13 application starting in development on http://0.0.0.0:3000 => Call with -d to detach => Ctrl-C to shutdown server foooooooooo [ActiveEnum::FormHelpers::Formtastic2, Formtastic::Helpers::ErrorsHelper, Formtastic::Helpers::ActionsHelper, Formtastic::Helpers::ActionHelper, Formtastic::Helpers::InputsHelper, Formtastic::LocalizedString, Formtastic::Helpers::FieldsetWrapper, Formtastic::Helpers::InputHelper, Formtastic::Helpers::FileColumnDetection, Formtastic::Helpers::Reflection, Formtastic::HtmlAttributes, JSON::Ext::Generator::GeneratorMethods::Object, ActiveSupport::Dependencies::Loadable, V8::Conversion::Object, Kernel]
content of the initializer:
ActiveEnum.setup do |config| # Extend classes to add enumerate method config.extend_classes = [ ActiveRecord::Base ] # Return name string as value for attribute method config.use_name_as_value = true # Storage of values (:memory, :i18n) config.storage = :memory require 'active_enum/form_helpers/formtastic2' end ActiveEnum.define do enum(:chain) do value :id => 1, :name => 'templates' value :id => 2, :name => 'global' value :id => 3, :name => 'routing' value :id => 4, :name => 'transport' end enum(:policy) do value :id => 1, :name => 'accept' value :id => 2, :name => 'deny' value :id => 3, :name => 'pass' end end
model:
class FilterRule < ActiveRecord::Base
enumerate :policy, :with => ::Policy
...
Since I can be a bozo, I created a model with a field called kind_of. Then when I made this field enumerable, it overrode the ruby kind_of? method. This caused my rspec generated controller test to fail because .should be_a must reference the kind_of? method. Perhaps you could check the methods array when enumerating and throw an exception to keep bozos like me on the straight and narrow?
There is a form. It seems select
's checked
value isn't set currently. Yeah, Rails checks model.color
and gets red
but not 1
. But db's values is 1
instead. Oops, checked value is wrong, that why current value of select box is blank, amn't I right?
Hey there!
I'm currently working on upgrading a legacy app that's utilizing Formtastic and have noticed that it looks like the helper for that got removed sometime around 0.9.12. Is there any sort of workaround I can use to reintroduce support for Formtastic? Thanks!
@adzap, do have plans (or ideas) to provide JS helpers for things like enum declaration or client side validation?
I use the client_side_validations gem which automagically converts rails validations of type ActiveModel::EachValidator
into a hash that works with their javascript library. It's wonderful.
For validations that it doesn't support out of the box, you can add your own -- which is what I would do for validates_inclusion_of
Thanks again for your great gem.
The question methods do not work when the option
config.use_name_as_value = true
is set.
class Conversation < ActiveRecord::Base
enum :status, [ :active, :archived ]
end
conversation.new(status: :active)
conversation.active? # => true
Syntax is shorter than
user.sex?(:male) # => true
user.sex?(:Male) # => true
user.sex?('Male') # => true
Special note: In case of method overlap, ActiveRecord::Enum let's you define suffix or prefix.
enum :status, [ :active, :archived ], prefix: true
conversation.status_active? # => true
Valid values are for prefix/suffix
true, false(default), string
Looking at the code referenced in this issue, it doesn't seem possible to create an enum where the id is a string.
You can see this in an example:
class Sex < ActiveEnum::Base
value :id => 'm', :name => 'Male'
value :id => 'f', :name => 'Female'
end
will result in:
> Sex['m']
=> nil
Lookup by name works as expected:
> Sex['male']
=> "m"
Hello @adzap !
I have a question... Why do we use id
s instead of name
s to identify a model's value? Isn't it a duplication?
I think this produces problems. First of all a guide's text says about it: If you change the order of values defined in an enum which don’t have explicit ids, then the ids will change. This could corrupt your data if the enum values have been stored in a model record, as they will no longer map to the original enum. We have three "fields" (id, name, i18n_name/symbol/etc...) instead of two (name, presentation_name_such_as_symbol). For why?
The second is that select
's checked value isn't set currently. Yeah, Rails checks model.color
and gets red
but not 1
. But db's values is 1
instead. Oops, checked value is wrong, amn't I right?
Thanx.
The readme doesn't mention that you have to set
config.storage = :i18n
In the initializer to enable i18n.
It might be a good idea to auto set this when active_enum:locale is installed.
We have the following behaviour:
MyApp::Enums::SomeCollection[id] # Translated text representing the key
MyApp::Enums::SomeCollection[key] # The id associated with the key
Why is there no easy way of retrieving the key
which represents the id
? The closest thing I've found is doing this:
arr = MyApp::Enums::SomeCollection.send(:store).send(:_values)
Hash[arr][<id>] # The key I want
I would really like to avoid Monkey Patching or calling private methods, and if the maintainers think this is a reasonable requirement I can come up with a pull request.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.