GithubHelp home page GithubHelp logo

adzap / active_enum Goto Github PK

View Code? Open in Web Editor NEW
126.0 126.0 33.0 256 KB

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

Ruby 100.00%

active_enum's People

Contributors

adzap avatar felixbuenemann avatar kengos avatar kuraga avatar mariuspopaadrian avatar petergoldstein avatar r10r avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

active_enum's Issues

Deprecation under rails 3.1

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

Add functionality to get id and name of enum by a method

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.

String keys in database

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

Access Enum as Constant

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.

Formtastic Support

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!

Rails 4 compatibility

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

Using ids instead of names to store

Hello @adzap !

I have a question... Why do we use ids instead of names 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.

Attribute isn't translated if id isn't a Fixnum

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.

plans to provide helpers for javascript or client_side_validations

@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.

detection of method collisions when enumerating attributes

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?

to_select method to return list based on specific enums

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] ]

Add enumerate method fails on Rails 6.1

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.

Provide rspec matcher out of the box

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

Checked values are empty

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?

Retrieving the key as well as the `id` and `name`

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.

Enum IDs Can't Be Strings

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"

Generate boolean method like ActiveRecord::Enum

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

ActionView::Template::Error (Unable to find input class for enum)

Hi,

I get an error from formtastic. What am I doing wrong?

  • Created the enum classes in the initializer.
  • used 'enumerate' to enumerate the model attribute
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 ...

Reopen issue #21 (string id's)?

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.