Rails global enums?

I have elements in my database schema that are integers and are set to a specific number that maps to the element. For example, a column named assign_type might have the value 0 = Unknown, 1 = Medical, 3 = Trial, etc. I don’t want to use magic numbers in my rails code and would prefer the Enum solution to make the code more convenient and readable. In addition, there is more than one table that has this destination_type column, so I want to be able to use "enumeration" for the address of other columns.

I thought of having a global enumeration element, as I would need to access this in my model, controller and view. Perhaps it is less likely that I need to access it in my model, but definitely in the controller and in the view.

Is there a good way to handle this?

+3
source share
5 answers

It may be less likely that I need access to it in my model, but definitely inside the controller and view.

Are you sure? When you talk about the 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 belong to the same model, you can save them directly in the model itself:

class Item < ActiveRecord::Base
  STATUS_UNKNOWN = 0
  STATUS_MEDICAL = 3
end

class Item
  def my_method
    STATUS_UNKNOWN
  end
end

Item::STATUS_UNKNOWN # => 0
Item.new.my_method # => 0

, .

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

, , .

+4

...

lib :

integer_to_enum.rb

:

module IntegerToEnum

  class << self

    def included(klass)
      klass.extend(ModelClassMethods)
    end

  end

  module ModelClassMethods

    def fields_to_enum(options={})
      class_eval <<-end_eval
        def set_enum_options
          @enum_options = #{options.inspect}
        end
      end_eval

      options.each_pair do |k,v|
        class_eval <<-end_eval
          def #{k.to_s}
            self.set_enum_options
            @enum_options[:#{k.to_s}][read_attribute(:#{k.to_s}).to_i]
          end

          def #{k.to_s}=(v)
            self.set_enum_options
            unless @enum_options[:#{k.to_s}].include?(v)
              return false
            end

            write_attribute(:#{k.to_s}, @enum_options[:#{k.to_s}].index(v))
            @#{k.to_s}
          end
        end_eval
      end
    end
  end

end

enviroment.rb , 'end'

ActiveRecord::Base.send :include, IntegerToEnum

, "" Integer:

class YourModel < ActiveRecord::Base

  fields_to_enum :appointment_type => [:unknown, :medical, :trial], :other_field_type => [:type_a, :type_b, :type_c]

end

- :

m = YourModel.find(1)
m.appointment_type #=> :unknown
m.appointment_type = :trial #=> :trial
m.save #=> and this will save with the index value of the array definition, since ':trial' is in the 3er position, the sql resulting will save with this number

..

+1

,

0

You may have a table that contains all this information and caches the original table when the environment boots.

That way, you can even implement referential integrity between a table appointment_types, as well as a table appointment_type_idin other tables.

0
source
0
source

Source: https://habr.com/ru/post/1713483/


All Articles