Module: HasHelpers::Constant
- Extended by:
- ActiveSupport::Concern, T::Helpers
- Included in:
- Color, Application, HasHelpers::Cards::CardCustomField, HasHelpers::Cards::CardDataType, HasHelpers::Cards::CardIdentifier, HasHelpers::Cards::CardLayoutType, HasHelpers::Cards::CardVariantType, LinkType, NotificationAlertStatus, NotificationAlertType, Operation, ResourceType, Option, TimeZone
- Defined in:
- lib/has_helpers/constant.rb
Overview
This module can be included into any standard ActiveRecord model to make its records available as databased-backed "constants". The definition of these records is contained in the individual model classes.
Seeding Constants
Each Constant class contains its own constant definitions and the appropriate database
records can be seeded by calling the .seed! method. This can easily be done in a migration
For example:
# app/constants/my_const.rb
class MyConst < ActiveRecord::Base
include HasHelpers::Constant
define_constants "Foo", "Bar"
end
# db/migrate/20190226170740_seed_my_const.rb
::MyConst.seed!
However, care must be given to avoid referencing Constants in code which is executed
during application load. Referencing a Constant for which there is no matching record
in the database will cause an exception. In a Rails application such a situation would
make it impossible to run the db:seed Rake task.
class Foo
validates :attr, inclusion: MyConst::ALL.map(&:name) # <- This will cause an exception unless all MyConst records have been seeded.
To avoid that problem you should structure your code to only use constants after the applications has been loaded. See also the notes below regarding Lazy Attributes.
Constant Names Without Referencing Constants
It is possible to access the names of the constant records using just the configuration.
A list of constant names is return by calling .constant_names on a Constant class.
This does not rely on having database records seeded and can thus be used in cases
where records may not have been seeded. While this approach is currently limited
it does provide a working alternative to the broken example above.
class Foo
validates :attr, inclusion: MyConst.constant_names # <- This will work regardless of whether the MyConst records have been seeded.
Examples
class FujitaScale include HasHelpers::Constant define_constants "F1", "F2", "F3", "F4", "F5" end
FujitaScale::F1 # => <FujitaScale name="F1">
FujitaScale::ALL # => [<FujitaScale name="F1">, <FujitaScale name="F2">, <FujitaScale name="F3">, <FujitaScale name="F4">, <FujitaScale name="F5">]
class Alignment
include HasHelpers::Constant
# See also the section on Shared Attributes below.
define_constants(
"Top".to_constant(type: "Vertical"),
"Middle".to_constant(type: "Vertical"),
"Bottom".to_constant(type: "Vertical"),
"Left".to_constant(type: "Horizontal"),
"Center".to_constant(type: "Horizontal"),
"Right".to_constant(type: "Horizontal")
)
define_constant_group "VERTICAL" do
[TOP, MIDDLE, BOTTOM]
end
define_constant_group("HORIZONTAL") { [LEFT, CENTER, RIGHT] } # Terser syntax
end
Alignment::HORIZONTAL # => [<Alignment name="Left" type="Horizontal">, <Alignment name="Center" type="Horizontal">, <Alignment name="Right" type="Horizontal">]
Alignment::TOP # => <Alignment name="Top" type="Vertical">
Key Attribute
When defining a constant a value for the key attribute is automatically generated
from the given name. From the examples above the Alignment constant with the name
"Top" is assigned the key TOP. That means that Alignment::TOP will be Ruby constant
through which users should reference.
In some cases the given name of the defined constant is not convertible to a valid key (Ruby constant name), or the resulting key is not desirable. In these cases it is possible to explicitly set the key value.
class AgeBand
include HasHelpers::Constant
define_constant "0-17".to_constant(key: "ZERO_TO_SEVENTEEN") # Explicit key
Shared Attributes
Sometimes many constants will have attributes in common. Such common attributes may
be assigned by passing them into a define_constants call. In this case each constant
definition will be assigned the common attributes.
The constants from the previous example can be rewritten as the following:
define_constants "Top", "Middle", "Bottom", type: "Vertical"
define_constants "Left", "Center", "Right", type: "Horizontal"
Lazy Attributes
If attributes need to be dynamically resolved, then wrap them in a block. This allows a constant definition to reference another constant without needing to load the other constant immediately.
class Registration
define_constants(
# Do not force the Exam::S4 constant to be loaded immediatily.
"Registered Options Principal".to_constant(abbreviation: "OP", exam: proc { ::Exam::S4 })
# The +:key+ option must _not_ be lazy! If +:name+ is given without +:key+ then +:name+ must likewise _not_ be lazy.
"Registered Options Principal".to_constant(key: "OP", abbreviation: "OP", exam: proc { ::Exam::S4} }
Defined Under Namespace
Modules: ClassMethods, InstanceMethods Classes: Definition, Proxy
Class Method Summary collapse
Class Method Details
.included(klass) ⇒ Object
274 275 276 |
# File 'lib/has_helpers/constant.rb', line 274 def self.included(klass) klass.include(InstanceMethods) # Use include rather than prepend so to not override user-defined instance methods on the class. end |