Giter VIP home page Giter VIP logo

classy_enum's People

Contributors

beerlington avatar fotanus avatar indrekj avatar inopinatus avatar jordpo 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

classy_enum's Issues

Mongoid support

I really like this gem, but it works only with ActiveRecord. Mongoid support would be excellent :)

Rails 5.x update

Hello there 😄

I was wondering if there are any plans on updating the gem to Rails 5.x and Ruby 2.4.x? 🤔
Or is it compatible already?

Also, what is the status of this gem, it's still being maintained?

I found the concept interesting for state machines and general enums (used in two projects some time ago, one from real life and one pet project) 😆

Docs on Owner

It appears that the docs are incorrect regarding owner. I have two models using the same classy_enum. Without defining owner I am able to call owner on the object and get the parent class. So it appears you do not have to explicitly define the owner.

Classy_enum with actual enum fields?

Hey man, long time user of classy_enum, awesome work!

I'm working in rails 4.2 and pg, and I have a field that I want to just call an enum right at the database level since such a thing is possible now. Could you maybe write a quite how-to in the readme about how to use that instead of a string field?

Drop support for Rails 3.x

Rails 4.2 is right around the corner, no need to support this many versions of Rails. Not sure if 3.2 needs to be supported, but it's almost 3 years old.

validates_uniqueness_of in Rails 3.1

I know you've listed this as a known issue, but it's now a major blocker for me :(

triggering validations on my model that uses validates_uniqueness_of for an enum column causes this error:

TypeError: Cannot visit ProviderTwitter
from /Users/bradrobertson/.rvm/gems/ruby-1.9.3-p0@influitive/gems/arel-2.2.1/lib/arel/visitors/visitor.rb:25:in `rescue in visit'

TypeError for classy_enum after upgrading Rails from 3.0.1 to 3.0.7

I've just upgraded rails on my development mac from 3.0.1 to 3.0.7. Tried to run rspec (2.6.0) (with factory_girl_rails 1.0.1) and got errors in all tests where models use classy_enum (0.9.1) gem for status implementation. Rails itself runs without problems, but rspec tests fails. Have no idea what causes the error.

Posted to stackoverflow with code examples:
http://stackoverflow.com/questions/6464221/typeerror-for-classy-enum-after-upgrading-rails-from-3-0-1-to-3-0-7

Eager loading with inludes() returns String, not Enum

Here my three classes :

class Bicycle < ActiveRecord::Base
  has_many :ratings, class_name: "BicycleRatings"
  has_many :parts, through :ratings
end
class BicycleRating < ActiveRecord::Base
  belongs_to :bicycle
  belongs_to :part, class_name: "BicyclePart", foreign_key: :bicycle_part_id
  classy_enum_attr :condition, default: :usable
end
class BicyclePart < ActiveRecord::Base
  has_many :ratings, class_name: "BicycleRatings"
  has_many :bicycles, through: :ratings
end

Here what I have when I try to get the condition of a bicycle part by eager loading the ratings :

pry(main)> Bicycle.first.parts.includes(:ratings).select( "bicycle_ratings.condition" ).first.condition
  Bicycle Load (0.4ms)  SELECT "bicycles".* FROM "bicycles" ORDER BY "bicycles"."id" ASC LIMIT 1
  BicyclePart Load (0.3ms)  SELECT bicycle_ratings.condition FROM "bicycle_parts" INNER JOIN "bicycle_ratings" ON "bicycle_parts"."id" = "bicycle_ratings"."bicycle_part_id" WHERE "bicycle_ratings"."bicycle_id" = ? ORDER BY "bicycle_parts"."id" ASC LIMIT 1  [["bicycle_id", 1]]
=> "usable"
pry(main)> condition.class
=> String

Condition::Usable is expected. I don’t know how to get it :-)

Wierd failure when using with jruby

Hello,

I'm using gem version 3.4.0 and on ruby 2.0 it works well, but with jruby 1.7.11 fails.

Here is my app/enums/status.rb:

class Status < ClassyEnum::Base
end

class Status::Started < Status
end

class Status::Running < Status
end

class Status::Failed < Status
end

class Status::Complete < Status
end

Here is a stack trace.

NoMethodError: super: no superclass method `visit_Status_Started'
              inherited at /home/craw/.rvm/gems/jruby-1.7.11/gems/classy_enum-3.4.0/lib/classy_enum/base.rb:72
                 (root) at /home/craw/app/app/enums/status.rb:4
                require at org/jruby/RubyKernel.java:1085
                require at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/dependencies.rb:251
        load_dependency at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/dependencies.rb:236
                require at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/dependencies.rb:251
                 (root) at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/dependencies.rb:1
        require_or_load at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/dependencies.rb:359
  load_missing_constant at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/dependencies.rb:502
                   each at org/jruby/RubyArray.java:1613
          const_missing at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/dependencies.rb:192
          const_missing at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/dependencies.rb:190
                   each at org/jruby/RubyArray.java:1613
            constantize at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/inflector/methods.rb:230
            constantize at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/inflector/methods.rb:229
            constantize at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/core_ext/string/inflections.rb:54
       classy_enum_attr at /home/craw/.rvm/gems/jruby-1.7.11/gems/classy_enum-3.4.0/lib/classy_enum/active_record.rb:56
                  Batch at /home/craw/app/app/models/batch.rb:3
                require at org/jruby/RubyKernel.java:1085
                require at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/dependencies.rb:251
        load_dependency at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/dependencies.rb:236
                require at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/dependencies.rb:251
                 (root) at /home/craw/app/app/models/batch.rb:1
                 (root) at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/dependencies.rb:1
        require_or_load at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/dependencies.rb:359
                   each at org/jruby/RubyArray.java:1613
  load_missing_constant at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/dependencies.rb:502
          const_missing at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/dependencies.rb:192
                   each at org/jruby/RubyArray.java:1613
          const_missing at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/dependencies.rb:190
            constantize at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/inflector/methods.rb:230
            constantize at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/inflector/methods.rb:229
       safe_constantize at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/inflector/methods.rb:260
       safe_constantize at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/core_ext/string/inflections.rb:66
    _default_wrap_model at /home/craw/.rvm/gems/jruby-1.7.11/gems/actionpack-3.2.16/lib/action_controller/metal/params_wrapper.rb:152
  _set_wrapper_defaults at /home/craw/.rvm/gems/jruby-1.7.11/gems/actionpack-3.2.16/lib/action_controller/metal/params_wrapper.rb:169
              inherited at /home/craw/.rvm/gems/jruby-1.7.11/gems/actionpack-3.2.16/lib/action_controller/metal/params_wrapper.rb:133
              inherited at /home/craw/.rvm/gems/jruby-1.7.11/gems/actionpack-3.2.16/lib/abstract_controller/railties/routes_helpers.rb:7
                require at org/jruby/RubyKernel.java:1085
                require at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/dependencies.rb:251
        load_dependency at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/dependencies.rb:236
                require at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/dependencies.rb:251
              inherited at /home/craw/.rvm/gems/jruby-1.7.11/gems/actionpack-3.2.16/lib/action_controller/railties/paths.rb:7
                 (root) at /home/craw/app/app/controllers/batch_controller.rb:1
                 (root) at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/dependencies.rb:1
        require_or_load at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/dependencies.rb:359
                   each at org/jruby/RubyArray.java:1613
              depend_on at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/dependencies.rb:313
                   each at org/jruby/RubyArray.java:1613
     require_dependency at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/dependencies.rb:225
            eager_load! at /home/craw/.rvm/gems/jruby-1.7.11/gems/railties-3.2.16/lib/rails/engine.rb:444
          instance_exec at org/jruby/RubyBasicObject.java:1565
                    run at /home/craw/.rvm/gems/jruby-1.7.11/gems/railties-3.2.16/lib/rails/initializable.rb:30
            eager_load! at /home/craw/.rvm/gems/jruby-1.7.11/gems/railties-3.2.16/lib/rails/engine.rb:443
                   each at org/jruby/RubyArray.java:1613
            eager_load! at /home/craw/.rvm/gems/jruby-1.7.11/gems/railties-3.2.16/lib/rails/engine.rb:441
               Finisher at /home/craw/.rvm/gems/jruby-1.7.11/gems/railties-3.2.16/lib/rails/application/finisher.rb:53
       run_initializers at /home/craw/.rvm/gems/jruby-1.7.11/gems/railties-3.2.16/lib/rails/initializable.rb:55
       run_initializers at /home/craw/.rvm/gems/jruby-1.7.11/gems/railties-3.2.16/lib/rails/initializable.rb:54
                require at org/jruby/RubyKernel.java:1085
                require at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/dependencies.rb:251
        load_dependency at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/dependencies.rb:236
                require at /home/craw/.rvm/gems/jruby-1.7.11/gems/activesupport-3.2.16/lib/active_support/dependencies.rb:251
            initialize! at /home/craw/.rvm/gems/jruby-1.7.11/gems/railties-3.2.16/lib/rails/application.rb:136
         method_missing at /home/craw/.rvm/gems/jruby-1.7.11/gems/railties-3.2.16/lib/rails/railtie/configurable.rb:30
                require at org/jruby/RubyKernel.java:1085
                 (root) at script/rails:6

I see you're supporting only CRuby, but probably can help.

Best practice for name-spacing or subclassing a Classy Enum?

Imagine I had several different models having a status, say Order with statuses "open", "invoiced", "paid", and `Product' with statuses "in_stock", "ordered", "discontinued".

Currently I am appending the class name, so in app/enums I have OrderStatus and ProductStatus, then in the model, use the :enum option, like

class Product << ActiveRecord::Base
  classy_enum_attr :status, enum: 'ProductStatus'
  # and so on
end

It works (even to my delight, in my I18n files). The doc suggests use of the :enum option is a special case. Is there a better way?

And, as an aside... I have been doing Rails for years, and have come up with a number of ugly patterns that solve some of these issues. I wish I had known about your gem -- it's a thing of beauty. Thanks!

destroyer destroy folder when not empty

Thanks for the wonderful gem. Can't image myself living without it right now.

The title says it all. You can see the following output:

# All enums are there
$ ls app/enums
delivery_method.rb  job_state.rb  service_kind.rb

# Creating a new enum
$ rails generate classy_enum PaymentProcessor bank_deposit
       exist  app/enums
      create  app/enums/payment_processor.rb
      invoke  rspec
       exist    spec/enums
      create    spec/enums/payment_processor_spec.rb

# Ops, typo, let me destroy it
$ rails destroy classy_enum PaymentProcessor bank_deposit
      remove  app/enums
      remove  app/enums/payment_processor.rb
      invoke  rspec
      remove    spec/enums
      remove    spec/enums/payment_processor_spec.rb

# omg, where are my enums?!?!
$ ls app/enums
ls: cannot access app/enums: No such file or directory

validation failed: ... not included in the list (Rails 4)

In Rails 4, with this model

class Player < ActiveRecord::Base
  classy_enum_attr :strategy
end

results in this error

$ ModelName.create!
(0.1ms) begin transaction
(0.1ms) rollback transaction
ActiveRecord::RecordInvalid: Validation failed: Strategy is not included in the list

However, this works fine when we specify a parameter:

class Player < ActiveRecord::Base
  classy_enum_attr :strategy, default: 'offensive'   #or serialize_as_json: true
end

:(

Question: Using classy enum to query with AR?

I'm a bit irritated on how to use classy enum correctly in some cases.

Given the following enum definitions:

class House::PictureType < ClassyEnum::Base; end

class House::PictureType::Summer < House::PictureType; end
class House::PictureType::Winter < House::PictureType; end

I cannot use classy enum in AR queries like this:

Pictures.where(kind: House::PictureTypes::Summer)

Do I understand correctly that the right way to do this is to instantiate a enum and call #to_s?

Pictures.where(kind: House::PictureTypes::Summer.new.to_s)

This feels very wired, mainly because I think of enums as constant types (value objects) and it makes no sense to instantiate them. Also, is there a "better" way to get the enums value representation then calling #to_s? Why can't I call House::PictureTypes::Summer.to_s directly as every instance of it will always return summer (AFAIK)

Rails 3.1.0

classy_enum is not compatible with Rails 3.1.0.

undefined method `is?' for portrait:OrientationTypePortrait

#build --> #find?

It seems #find is a significantly better name for what #build is actually doing. Why the change from #find to #build?

2 tests failing - extra id parameter in AR?

Clone, bundle, rspec. Two tests failed?

There's an id extra. Isn't that how AR should behave? adding id automatically? (I don't know much about AR, so correct me if I'm wrong)

bundle exec rspec                                                      !352
-- create_table(:dogs, {:force=>true})
   -> 0.0137s
-- create_table(:other_dogs, {:force=>true})
   -> 0.0006s
-- create_table(:allow_blank_breed_dogs, {:force=>true})
   -> 0.0005s
-- create_table(:allow_nil_breed_dogs, {:force=>true})
   -> 0.0005s
-- create_table(:active_dogs, {:force=>true})
   -> 0.0006s
-- create_table(:cats, {:force=>true})
   -> 0.0005s
-- create_table(:other_cats, {:force=>true})
   -> 0.0005s
-- initialize_schema_migrations_table()
   -> 0.0006s
-- assume_migrated_upto_version(1, ["db/migrate"])
   -> 0.0002s
...........................FF.....................................

Failures:

  1) Cat should correctly serialize without the owner reference
     Failure/Error: abyssian.to_json.should == "{\"cat\":{\"breed\":\"abyssian\"}}"
       expected: "{\"cat\":{\"breed\":\"abyssian\"}}"
            got: "{\"cat\":{\"breed\":\"abyssian\",\"id\":null}}" (using ==)
     # ./spec/classy_enum_owner_reference_spec.rb:34:in `block (2 levels) in <top (required)>'

  2) Cat should convert the enum to a string when serializing
     Failure/Error: persian.to_json.should == "{\"other_cat\":{\"breed\":{}}}"
       expected: "{\"other_cat\":{\"breed\":{}}}"
            got: "{\"other_cat\":{\"breed\":{},\"id\":null}}" (using ==)
     # ./spec/classy_enum_owner_reference_spec.rb:38:in `block (2 levels) in <top (required)>'

Finished in 0.23622 seconds
66 examples, 2 failures

Failed examples:

rspec ./spec/classy_enum_owner_reference_spec.rb:33 # Cat should correctly serialize without the owner reference
rspec ./spec/classy_enum_owner_reference_spec.rb:37 # Cat should convert the enum to a string when serializing

Undocumented breaking change (Cannot visit <Enum>)

I noticed that 963ac91 removed some visitor support and changed the specs. I upgraded to the 4.0 gem version and am seeing that lines similar to Dog.where(:breed => Breed.build('golden_retriever')) now error. I didn't see any mention of that change in the CHANGELOG, but maybe I'm missing something?

Uninitialized Constant when Loading Classy Enum in 4.0.0

I added a 4.0.0 classy_enum to an active record like so (ruby: 2.1.4, rails: 4.2.0):

class Membership < ActiveRecord::Base
  include ClassyEnum::ActiveRecord
  classy_enum_attr :status, class_name: 'MembershipStatus'
  ...
end

This active record joins two other tables (User and Group), and defaults the enum value to "pending".

Attempting to load the enum from the database yields:

NameError: uninitialized constant MembershipStatus

For example, with:

Group.find(2).memberships

Downgrading to 3.5.0 without any code changes fixes the problem:

Group.find(2).memberships[0].status.text
 => "Pending"

Add support for validation :on and :if options

As it stands, classy_enum_attr macro isn't very flexible, and if I want to customize validation a bit with if and on options, I have to monkey_patch method and delete validation defined by the gem. I guess something like validate_on: and validate_if options for this method would be pretty useful and easy to add, I could prepare a PR if you don't mind.

Question: Is this the right fit for my usecase?

So I have two places where I think this would work well. We have integrations for Twitter, Facebook and Instagram. Currently we're storing these things in an STI-ish table... but we also have a table of "types" that we update when we add a new type.

For programatic things, it's strange to store that kind of thing in a DB table, since it would essentially break if the table didn't have an entry.

Another instance is with "types" of fields... like we're going to have people choose between "image, video, color, text", and depending on the type, when you go to edit, it would display a different kind of field.

Are these good usecases for classy_enum? I'm trying to figure out the dividing line between STI and enums.

Problem with default value

When run in rails console, It's normal do happen this?

Point.new
NoMethodError: super: no superclass method `transaction_type=' for #Point:0x00000101913578

My Point definition

class Point < ActiveRecord::Base
    include ClassyEnum::ActiveRecord
  classy_enum_attr :transaction_type, default: 'issuance'
    delegate :do, to: :transaction_type
  belongs_to :loyalty
end
}
class TransactionType < ClassyEnum::Base
    owner :point
end

class TransactionType::Issuance < TransactionType
    def do
        point.loyalt.balance+=point.val
    end 
end

class TransactionType::Redemption < TransactionType
    def do
        point.loyalt.balance-=point.val
    end 
end

I'm following the README file and this should work..

May someone help me?

"rails destroy classy_enum EnumName" deletes all enums

This command is not in the documentation but I decided to give it a try anyway and at first glance I thought it had worked. It turned out afterwards, however, that it had deleted all enums.

$ rails destroy classy_enum Level
remove app/enums
remove app/enums/level.rb
invoke rspec
remove spec/enums
remove spec/enums/level_spec.rb

It would be nice if it behaved as expected and only deleted the one whose name was provided in the end of the command, following the pattern of "rails destroy controller controler_name" etc.

Clean up specs

The specs haven't been refactored in many years, time for an overhaul.

CircularReferenceError with rails 'to_json' method

Hi,

I added an enum to my (working) class, and now i get CircularReferenceError when i try to convert my instance into JSON.

By default class is serialized with the enum, which is serialized with the owner... which is serialized with the enum :-)

I think the generator (or the base class) should override as_json to except the owner attribute.

I did this into by base enum class:
def as_json(options = {})
{:sym => to_s, :name => name}
end

Clean up how code is injected into Active Record

Need to figure out what the best practices are these days for gems that extend Active Record. Injecting it in all models feels dirty. Maybe it's time to require users to explicitly include it in models.

How to update many records at once?

I'm using your gem and trying to do this:

 jobs.update_all job_state: JobState::WaitingTranslation

but it throws an error. is possible to make it works to update multiple records?

Rails 4.1 enums

Hi,

I have some questions for discussion:

  1. What are the advantages of keep using classy_enum after rails 4.1 introduced enums?
  2. How easy would be to migrate?
  3. Should we stop using class enum if working with rails 4.1+? Why not?

Maybe the readme should answer this questions from now on.

Thanks for the great work you did on this gem so far!

Enum by default are empty in DB?

I'm using classy_enum on my model, like this:

classy_enum_attr :state, enum: 'MyModelState', default: :open

However when I do:

m = MyModel.create

If i search on the DB the field is NULL, not open.

If I do

m.state # #<MyModelState::Open:0x007fb46ac77bf0

But on DB is null, the issue with this is that this is not working

MyModel.where(state: [:open, :error_submitting])

Changing what's returned by #select_options

I have an enum for programming languages, and one of the options is C++; I call it Cpp since + cannot be in a class name. Calling #select_options in a view gives a select option shown to the user as Cpp, but I'd prefer if it could instead return C++.

A solution I found for this was to modify my config/locales/en.yml file to make cpp be associated with the string "C++", but I'm not sure if that's the "correct" way to do it. I'm not terribly familiar with i18n or the inner workings of classy_enum, so forgive me if this is a dumb question.

Update the readme to include a step about autoload_paths

I followed the steps in the readme to create an enum for Gender, however I kept getting the following error after updating my model:

NameError: uninitialized constant Gender

I ended up adding the following line to application.rb:

config.autoload_paths += %W(#{config.root}/app/enums)

For the record, I'm using Rails 4.1.6 and Ruby 2.2.0.

Should this step be in the Readme or is it assumed that we should know to update the paths?

Add Option to Store Integer Instead of String

I would like to be able to order my classy_enums by index in my database queries. Would it make sense to add an option to specify that classy_enums should be persisted as integers? For example:

classy_enum_attr :priority, :persist_as => :integer

Accessing enum in model returns String, not Enum?

Hi there,

I hope I am not missing something real simple, but I'm having an issue that makes classy_enum unusable!

Basically, my enum getters return String objects, rather than the enum class, as expected.

Here's a console excerpt that illustrates the issue:

irb(main):014:0> t = Task.new
=> #<Task id: nil, priority: nil, created_at: nil, updated_at: nil>
irb(main):015:0> t.priority = Priority::Low
=> Priority::Low
irb(main):016:0> t.save
   (0.1ms)  begin transaction
   (0.1ms)  rollback transaction
=> false
irb(main):017:0> t.errors
=> #<ActiveModel::Errors:0x007f889c033e38 @base=#<Task id: nil, priority: "Priority::Low", created_at: nil, updated_at: nil>, @messages={:priority=>["is not included in the list"]}>
irb(main):018:0> t.priority.class
=> String
irb(main):019:0> t.priority
=> "Priority::Low"

I've configured the enum just like in the example in the README... nothing fancy. At first I thought one of my other gems may have been interfering, but I've isolated this in an empty rails app (Rails 3.2.11).

enums/priority.rb:

class Priority < ClassyEnum::Base
end

class Priority::Low < Priority
end

class Priority::Medium < Priority
end

class Priority::High < Priority
end

task.rb:

class Task < ActiveRecord::Base
  classy_enum_attr :priority
end

migration:

class CreateTasks < ActiveRecord::Migration
  def change
    create_table :tasks do |t|
      t.string :priority

      t.timestamps
    end
  end
end

ClassyEnum build method performance

I was profiling some code in my app and found that build method is based on find method to search the Enum that comes from the database.

In my case, one of the enums has 14 different types, and for a specific use case where I instantiate about 2000 records from the database, each one with several classy_enum fields the current implementation is noticeable slow.

I implemented an additional find method only to use it in a benchmark. I'm not suggesting replacing the current implementation with this. It´s only used as POC.

class ClassyEnum::Base
  def self.find_fast(key = nil)
    @@found ||= Hash.new
    @@found[key] ||= begin
                       if block_given?
                         find(key, &block)
                       else
                         find { |e| e.to_s == key.to_s }
                       end
                     end
  end
end

And then run a benchmark:

Warming up --------------------------------------
find          5.548k i/100ms
find_fast   247.291k i/100ms
Calculating -------------------------------------
find          57.654k (± 1.6%) i/s -    288.496k in   5.005099s
find_fast   2.509M (± 3.9%) i/s -     12.612M in   5.036393s

Comparison:
find_fast:  2508639.9 i/s
find:    57654.4 i/s - 43.51x  (± 0.00) slower

I think that something like this is a huge improvement and also saves a lot of cpu cycles.

Also, in the current implementation, I think there is a map call that can be removed

      def find(key=nil)
        if block_given?
          super
        elsif map(&:to_s).include? key.to_s
          super { |e| e.to_s == key.to_s }
        end
      end

This is the same, no need to map and test for include?, or maybe I don't know something

      def find(key=nil)
        if block_given?
          super
        else
          super { |e| e.to_s == key.to_s }
        end
      end

Thanks for this great gem! 😃

Cannot visit Priority::Medium

I have an scope like this:

  class << self
    def my_scope
      where(:priority => Priority[:medium])
    end
  end

When I call only the scope, that's ok. But when I use count appended to the scope, it gives me an error like this: Cannot visit Priority::Medium.

user.tasks.my_scope # works
user.tasks.my_scope.count # Cannot visit Priority::Medium

But if I change the scope to where(:priority => Priority[:medium].to_s) it works with both queries. I don't know why it's not being interpreted as a String, any clue?

Thanks.

Issue on 3.1.3 with loading of class constants and subdirectories

Hey,

Originally, I had my enums all in one file. However, this caused a problem in dev env because classes would be reloaded but not the subclasses. I think this is because rails only reloads based upon file names and doesn't know there are more classes defined in that file.

So I moved the sub enums into app/models/job_types/. JobType is my enum class and added app/models/job_types to the autoload directory in application.rb

However, this still causes more problems because the subclasses are still not loaded at all. However, the class constants are there because of the behavior in class_methods.rb#enum_classes methods where a class constant is assigned.

So my theory is that when rails goes to load the file, it sees an existing class constant for the file and skips loading of the file.

Interestingly, if I namespace the enum to the name of the directory, job_type...so classes are defined as JobType::JobTypeWebsite < JobType, and I access it JobType::JobTypeWebsite, it works.

The assigning of the class constant should optional or the behavior should change whether you explicitly define subclasses or not.

I'm going to fork this repo and work on it and get back to you.

Feature request: Better Mongoid support :)

class Property
  include Mongoid::Document

  classy_enum_attr        :type, :enum => 'PropertyType'
  classy_enum_attr        :furnished

super: no superclass method `type=' for #Property:0x007fb8fb25cb30

I have to declare the fields first! I thought it would be logical if it declares the String fields as a sideeffect?

  field :type,            type: String
  field :furnished,       type: String

  classy_enum_attr        :type, :enum => 'PropertyType'    
  classy_enum_attr        :furnished

Alternatively this should be possible with Mongoid using custom fields:

  field :type,   type: Enum, :enum => 'PropertyType'

Really cool :)

BTW: I still think macros are nice when you simply want a list of strings that are allowed and not a class with functions. You can always convert it into a real class if the need arises...

As a final note: In the *-mongoid gem, it looks real bad that the Mongoid::Document includes an ActiveRecord module. Why not extract the small AR part from Base into a separate module. Then call this module to do post config for that Orm if needed. Something like the following should work:

class Base
  def self.inherited(base)
     # stuff...

     orms = ClassyEnum::Orms.orms || []
     orms.each do |orm|
       "ClassyEnum::#{orm.to_s.camelize}::Config".constantize.config klass
     end

    # more stuff
  end
end

class ClassyEnum::ActiveRecord::Config
  def self.config klass
    Arel::Visitors::ToSql.class_eval do
      define_method "visit_#{klass.name.split('::').join('_')}", lambda {|value| quote(value.to_s) }
    end
  end
end

class ClassyEnum::Orms
   # orms that require special config
   def self.orms
      [:active_record] if defined?(Arel::Visitors::ToSql)
   end
end

Stack overflow when using classy_enum in the render function

Hi, I'm seeing some weird behavior that I can't explain and it seems to be related to classy_enum.
In my model I have:

class Message < ActiveRecord::Base
  classy_enum_attr :message_type

And I have the required enums and everything and it seems to work great. (I've used classy_enum in the past, so it's not my first enum. Other times didn't render a model with enums though)

The problem is that when I want to render a @message in the controller I get a stack overflow and sometimes (but not always) a complete server crash with class_enum in the stack

Users/ran/.rvm/gems/ruby-1.9.2-p290/gems/classy_enum-1.3.0/lib/classy_enum/class_methods.rb:58:in `const_get': uninitialized constant MessageTypeUser (NameError)
    from /Users/ran/.rvm/gems/ruby-1.9.2-p290/gems/classy_enum-1.3.0/lib/classy_enum/class_methods.rb:58:in `build'
    from /Users/ran/.rvm/gems/ruby-1.9.2-p290/gems/classy_enum-1.3.0/lib/classy_enum/attributes.rb:39:in `block (2 levels) in classy_enum_attr'
    from /Users/ran/dev/invi-backend/app/models/message.rb:16:in `to_s'
    from /Users/ran/dev/invi-backend/lib/messaging.rb:22:in `block in send'
    from /Users/ran/.rvm/gems/ruby-1.9.2-p290/gems/eventmachine-0.12.10/lib/em/deferrable.rb:141:in `call'
    from /Users/ran/.rvm/gems/ruby-1.9.2-p290/gems/eventmachine-0.12.10/lib/em/deferrable.rb:141:in `set_deferred_status'
    from /Users/ran/.rvm/gems/ruby-1.9.2-p290/gems/eventmachine-0.12.10/lib/em/deferrable.rb:180:in `fail'
    from /Users/ran/.rvm/gems/ruby-1.9.2-p290/gems/pusher-0.8.3/lib/pusher/channel.rb:51:in `block in trigger_async'
    from /Users/ran/.rvm/gems/ruby-1.9.2-p290/gems/eventmachine-0.12.10/lib/em/deferrable.rb:141:in `call'
    from /Users/ran/.rvm/gems/ruby-1.9.2-p290/gems/eventmachine-0.12.10/lib/em/deferrable.rb:141:in `set_deferred_status'
    from /Users/ran/.rvm/gems/ruby-1.9.2-p290/gems/eventmachine-0.12.10/lib/em/deferrable.rb:180:in `fail'
    from /Users/ran/.rvm/gems/ruby-1.9.2-p290/gems/em-http-request-0.3.0/lib/em-http/client.rb:310:in `unbind'
    from /Users/ran/.rvm/gems/ruby-1.9.2-p290/gems/eventmachine-0.12.10/lib/eventmachine.rb:1417:in `event_callback'
    from /Users/ran/.rvm/gems/ruby-1.9.2-p290/gems/eventmachine-0.12.10/lib/eventmachine.rb:256:in `run_machine'
    from /Users/ran/.rvm/gems/ruby-1.9.2-p290/gems/eventmachine-0.12.10/lib/eventmachine.rb:256:in `run'
    from /Users/ran/.rvm/gems/ruby-1.9.2-p290/gems/thin-1.2.11/lib/thin/backends/base.rb:61:in `start'
    from /Users/ran/.rvm/gems/ruby-1.9.2-p290/gems/thin-1.2.11/lib/thin/server.rb:159:in `start'
    from /Users/ran/.rvm/gems/ruby-1.9.2-p290/gems/rack-1.2.3/lib/rack/handler/thin.rb:14:in `run'
    from /Users/ran/.rvm/gems/ruby-1.9.2-p290/gems/rack-1.2.3/lib/rack/server.rb:217:in `start'
    from /Users/ran/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.0.10/lib/rails/commands/server.rb:65:in `start'
    from /Users/ran/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.0.10/lib/rails/commands.rb:30:in `block in <top (required)>'
    from /Users/ran/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.0.10/lib/rails/commands.rb:27:in `tap'
    from /Users/ran/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.0.10/lib/rails/commands.rb:27:in `<top (required)>'
    from script/rails:6:in `require'
    from script/rails:6:in `<main>'

It's hard to say what exactly is causing this.... but when I remove the classy enum definition in the model the crash doesn't happen.

Does this ring a bell? Have you any idea why is this or how to solve that?

thanks!

Adding subclasses at runtime

Hi there,

To save myself some tedious typing, I decided to do a little bit of metaprogramming to generate my subclasses, like so:

[0.13, 0.25, 0.5, 0.75, 1, 1.5, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30].each do |num|
    num_str = num.to_s.sub(/\./, '_')
    cls = Class.new(ContaminantDepth) do
        define_method :value do
            num
        end
    end
    ContaminantDepth.const_set("I#{num_str}", cls)
end

I do realize it may seem a little crazy to validate a range of numbers this way, but it is truly an enum, and I need special behaviour for some of these value, so I think this fits.

So it seems to work fine at first glance. However, doing a "ContamimantDepth.all" tells me that these dynamically-generated classes are not added to the enum list, and thus they do now validate in the active record column.

I think it may come down to this here in base.rb:

class << self
      def inherited(klass)
        return if klass.anonymous? # THIS ONE

        if self == ClassyEnum::Base
          klass.base_class = klass
        else

Can you point me in the right direction on this? It seems this was put in as a bug fix, but it may be blocking a legitimate use.

Thanks!

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.