Как лучше всего обрабатывать константы в Ruby при использовании Rails?

У меня есть некоторые константы, которые представляют допустимые параметры в одном из полей моей модели. Как лучше всего обрабатывать эти константы в Ruby?


person Miles    schedule 05.11.2008    source источник


Ответы (6)


Для этой цели вы можете использовать массив или хэш (в вашем окружении.rb):

OPTIONS = ['one', 'two', 'three']
OPTIONS = {:one => 1, :two => 2, :three => 3}

или, альтернативно, класс перечисления, который позволяет вам перечислять ваши константы, а также ключи, используемые для их связывания:

class Enumeration
  def Enumeration.add_item(key,value)
    @hash ||= {}
    @hash[key]=value
  end

  def Enumeration.const_missing(key)
    @hash[key]
  end   

  def Enumeration.each
    @hash.each {|key,value| yield(key,value)}
  end

  def Enumeration.values
    @hash.values || []
  end

  def Enumeration.keys
    @hash.keys || []
  end

  def Enumeration.[](key)
    @hash[key]
  end
end

из которого вы можете получить:

class Values < Enumeration
  self.add_item(:RED, '#f00')
  self.add_item(:GREEN, '#0f0')
  self.add_item(:BLUE, '#00f')
end

и используйте так:

Values::RED    => '#f00'
Values::GREEN  => '#0f0'
Values::BLUE   => '#00f'

Values.keys    => [:RED, :GREEN, :BLUE]
Values.values  => ['#f00', '#0f0', '#00f']
person Codebeef    schedule 05.11.2008
comment
Я решил пойти с этим решением. Должен сказать, он делает именно то, что мне нужно, и отлично работает с ActiveRecord. Благодарю вас! :D - person Miles; 07.11.2008

Я помещаю их прямо в класс модели, например:

class MyClass < ActiveRecord::Base
  ACTIVE_STATUS = "active"
  INACTIVE_STATUS = "inactive"
  PENDING_STATUS = "pending"
end

Затем при использовании модели из другого класса я ссылаюсь на константы

@model.status = MyClass::ACTIVE_STATUS
@model.save
person Micah    schedule 05.11.2008
comment
Это метод, а не класс. Нужно использовать class вместо def. - person weexpectedTHIS; 23.03.2012

Если это управляет поведением модели, то константы должны быть частью модели:

class Model < ActiveRecord::Base
  ONE = 1
  TWO = 2

  validates_inclusion_of :value, :in => [ONE, TWO]
end

Это позволит вам использовать встроенную функциональность Rails:

>> m=Model.new
=> #<Model id: nil, value: nil, created_at: nil, updated_at: nil>
>> m.valid?
=> false
>> m.value = 1
=> 1
>> m.valid?
=> true

В качестве альтернативы, если ваша база данных поддерживает перечисления, вы можете использовать что-то вроде Enum Плагин столбца.

person Dave    schedule 05.11.2008

В Rails 4.1 добавлена ​​release_notes.html#active-record-enums" rel="noreferrer">поддержка перечислений ActiveRecord.

Объявите атрибут перечисления, в котором значения сопоставляются с целыми числами в базе данных, но могут быть запрошены по имени.

class Conversation < ActiveRecord::Base
  enum status: [ :active, :archived ]
end

conversation.archived!
conversation.active? # => false
conversation.status  # => "archived"

Conversation.archived # => Relation for all archived Conversations

Подробное описание см. в его документации.

person Simone Carletti    schedule 09.01.2014
comment
Я думаю, что это лучший ответ. - person Islam Azab; 16.09.2015
comment
Будьте готовы получить исключения, когда вы попытаетесь присвоить какое-либо значение, которого нет в списке, в поле состояния, и будьте готовы получить конфликты имен, если вы добавите другое поле перечисления со значением [:active]. Реализация этой функции в Rails действительно неудобна. - person BitOfUniverse; 10.06.2016
comment
я сделал драгоценный камень для проверки включения перечислений github.com/CristiRazvi/enum_attributes_validation - person cristi_razvi; 13.11.2017

Вы также можете использовать его в своей модели внутри хеша, например:


class MyModel

  SOME_ATTR_OPTIONS = {
    :first_option => 1,
    :second_option => 2, 
    :third_option => 3
  }
end

И используйте это так:



if x == MyModel::SOME_ATTR_OPTIONS[:first_option]
  do this
end

person Dema    schedule 05.11.2008
comment
Спасибо за это. Это было вдохновением для группировки символов в массиве. - person chipairon; 09.04.2013

Вы также можете сгруппировать константы по темам, используя модуль --

class Runner < ApplicationRecord
    module RUN_TYPES
        SYNC = 0
        ASYNC = 1
    end
end

А потом есть,

> Runner::RUN_TYPES::SYNC
 => 0
> Runner::RUN_TYPES::ASYNC
 => 1
person Ady Rosen    schedule 28.01.2017