beerlington / classy_enum Goto Github PK
View Code? Open in Web Editor NEWA class-based enumerator gem for Rails
Home Page: http://beerlington.com/classy_enum/
License: MIT License
A class-based enumerator gem for Rails
Home Page: http://beerlington.com/classy_enum/
License: MIT License
I really like this gem, but it works only with ActiveRecord. Mongoid support would be excellent :)
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) 😆
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.
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?
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.
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'
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
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 :-)
The specs no longer run on travis in 1.8.7, and there's really no point in trying to support it anymore.
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.
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!
I would like to use Enum in a Rails app using Mongoid.
Looking at:
https://github.com/beerlington/classy_enum/blob/master/lib/classy_enum/active_record.rb
I see that everything would work just fine with Mongoid, except for the last line, where you extend ActiveRecord::Base with this module. So if you separate the two, we could easily define multiple ORM adapters...
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
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
:(
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)
classy_enum is not compatible with Rails 3.1.0.
undefined method `is?' for portrait:OrientationTypePortrait
It seems #find is a significantly better name for what #build is actually doing. Why the change from #find to #build?
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
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?
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"
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.
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.
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?
The Arel hacks are ugly and break JRuby support. Need to figure out if they're still needed in the latest versions of Rails.
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.
The specs haven't been refactored in many years, time for an overhaul.
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
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.
for example, you can't do
alert.priority_was.high?
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?
Hi,
I have some questions for discussion:
Maybe the readme should answer this questions from now on.
Thanks for the great work you did on this gem so far!
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])
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.
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?
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
Currently, can one classy_enum type hold another classy_enum value?
😃
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
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! 😃
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.
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.
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
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!
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!
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.