Ruby on Rails Global ActiveRecord::Enum
Use ActiveSupport::Concern
this feature created for dry
ing up model codes:
#app/models/concerns/my_enums.rb
module MyEnums
extend ActiveSupport::Concern
included do
enum status: [:active, :inactive, :deleted]
end
end
# app/models/my_model.rb
class MyModel < ActiveRecord::Base
include MyEnums
end
# app/models/other_model.rb
class OtherModel
include MyEnums
end
Read more
Rails global enums?
It may be less likely that I need to
access it in my model, but definitely
within the controller and view.
Are you sure? When you talk about database and schema, you are talking about the Model part of your application.
I think the best place to store these variables would be the model that uses them.
If these variables belongs to a single model you can store them directly in the model itself:
class Item < ActiveRecord::Base
STATUS_UNKNOWN = 0
STATUS_MEDICAL = 3
end
Then you can reference the values inside and outside the model scope
class Item
def my_method
STATUS_UNKNOWN
end
end
Item::STATUS_UNKNOWN # => 0
Item.new.my_method # => 0
When there is an enumeration of values, Rubyists often use hashes or arrays.
class Item
AVAILABLE_STATUSES = { :unkwnown => 0, :medical => 3 }
def self.statuses
self.AVAILABLE_STATUSES.keys.sort
end
def self.status_value(key)
self.AVAILABLE_STATUSES[:key]
end
end
Item::AVAILABLE_STATUS # => { :unkwnown => 0, :medical => 3 }
Item.statuses # => [:medical, :unkwnown]
Item.status_value(:medical) # => 3
If more than one model share the same logic, you can put it in a Module and mix the module in all Models that requires it.
Proper storage of enumeration models in Rails
Check out the ruby gem I've been working on called classy_enum. I'm pretty sure it does exactly what you're looking for. The README has some example usage, but the premise is that it lets you define multiple enum members as classes that can have different properties.
How to build dynamic enums in Rails 6 model concerns?
There are cleaner ways to do what I'm about to present, but it will accomplish what you're trying to do. Mind the brevity (I removed your associations to do a quick spot-check on my machine):
module Bookable
extend ActiveSupport::Concern
included do
STAGES = {
confirmed: 0,
completed: 1,
cancelled: 2,
issue_raised: 3
}.freeze
end
end
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
def self.acts_as_bookable_with(extra_stages = {})
include Bookable
enum stage: self::STAGES.merge(extra_stages)
end
end
class Mission < ApplicationRecord
acts_as_bookable_with({
awaiting_estimate: 4,
awaiting_payment: 5,
awaiting_report: 6,
report_sent: 7
})
end
If you want to define these on the class, it would look like this:
module Bookable
extend ActiveSupport::Concern
included do
STAGES = {
confirmed: 0,
completed: 1,
cancelled: 2,
issue_raised: 3
}.freeze
end
end
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
def self.acts_as_bookable_with(extra_stages)
include Bookable
if extra_stages.is_a?(Symbol)
extra_stages = self.send(extra_stages)
elsif extra_stages.is_a?(Hash)
# do nothing
else
raise TypeError, "can't find extra_stages from #{extra_stages.inspect}"
end
stages = self::STAGES.merge(extra_stages)
enum stage: stages
end
end
class Comment < ApplicationRecord
def self.extra_stages
{
awaiting_estimate: 4,
awaiting_payment: 5,
awaiting_report: 6,
report_sent: 7
}
end
acts_as_bookable_with(:extra_stages)
end
Note that we're calling acts_as_bookable_with
after we define our class method. Otherwise, we'll get undefined method error.
There isn't a whole lot of "bad" in having this in ApplicationRecord. It's not the most ideal way of doing it, but most of these acts_as_*
modules follow this exact pattern anyway and inject into ActiveRecord::Base
.
Rails: How do I validate uniqueness of certain types in an enum
validates :account_type, uniqueness: true, if: 'account_type == "user"'
The answer was based on @neydroid's answer, although that per se was incorrect, and he didn't respond to my request to fix it.
Ruby on Rails: get variable from include do
You cannot include this module into your controller. You could however try:
module MyEnums
extend ActiveSupport::Concern
Statuses = [:active, :inactive, :deleted]
included do
enum status: Statuses
end
end
And then in the controller:
MyEnums::Statuses
Related Topics
Callback for Active Storage File Upload
Why Won't Ruby Allow Me to Specify Self as a Receiver Inside a Private Method
Transliteration with Iconv in Ruby
How to Assign a Has_Many/Belongs_To Relation Properly in Rails Activerecord
Floating Point Precision in Ruby on Rails Model Validations
In Ruby How to Tell If a String Input Is in Uppercase or Lowercase
Rails Form Object with Reform-Rails with Collections Not Working or Validating
How to Specify a Regex Character Range That Will Work in European Languages Other Than English
What's the Nature of "Property" in a Ruby Class
Remote Form_Tag in Rails3 Without a Named Route
Interface Builder Not Seeing Outlets with MACruby
Should I Be Using Rails or Ruby for This Website Application? How
Argumenterror: Unknown Key: :Conditions. Valid Keys Are: :Class_Name, :Class, :Foreign_Key
What Is the Ruby Equivalent of the "This" Function in Java
What Do Ruby's Printf Arguments Mean
Does Anyone Have Parsing Rules for the Notepad++ Function List Plugin for Ruby and Rake