Ruby on Rails: Где определить глобальные константы?

Я только начинаю с моего первого Ruby on Rails webapp. У меня есть куча разных моделей, просмотров, контроллеров и т.д.

Я хочу найти хорошее место для определения определений действительно глобальных констант, которые применяются во всем моем приложении. В частности, они применяются как в логике моих моделей, так и в решениях, принятых в моих взглядах. Я не могу найти какое-либо СУХОЕ место для размещения этих определений там, где они доступны как для всех моих моделей, так и во всех моих представлениях.

Чтобы взять конкретный пример, я хочу константу COLOURS = ['white', 'blue', 'black', 'red', 'green']. Это используется повсюду, как в моделях, так и в представлениях. Где я могу определить его в одном месте, чтобы он был доступен?

Что я пробовал:

  • Константные переменные класса в файле model.rb, с которыми они наиболее связаны, например @@COLOURS = [...]. Но я не мог найти разумный способ определить его, чтобы я мог писать в своих представлениях Card.COLOURS, а не что-то вроде kludgy like Card.first.COLOURS.
  • Метод на модели, что-то вроде def colours ['white',...] end - та же проблема.
  • Метод в application_helper.rb - это то, что я делаю до сих пор, но помощники доступны только в представлениях, а не в моделях
  • Я думаю, что я, возможно, пробовал что-то в application.rb или environment.rb, но на самом деле это не кажется правильным (и они, похоже, тоже не работают).

Нет ли способа определить что-либо доступное как из моделей, так и из представлений? Я имею в виду, я знаю, что модели и представления должны быть раздельными, но, конечно же, в некоторых доменах они будут нуждаться в том, чтобы ссылаться на одни и те же знания домена.

Ответ 1

Если ваша модель действительно "ответственна" за константы, вы должны придерживаться их там. Вы можете создавать методы класса для доступа к ним без создания нового экземпляра объекта:

class Card < ActiveRecord::Base
  def self.colours
    ['white', 'blue']
  end
end

# accessible like this
Card.colours

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

class Card < ActiveRecord::Base
  @@colours = ['white', 'blue']
  cattr_reader :colours
end

# accessible the same as above

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

class Card < ActiveRecord::Base
  COLOURS = ['white', 'blue'].freeze
end

# accessible as
Card::COLOURS

Вы также можете создавать глобальные константы, доступные извне в инициализаторе, как в следующем примере. Это, вероятно, лучшее место, если ваши цвета действительно глобальны и используются в более чем одном контексте модели.

# put this into config/initializers/my_constants.rb
COLOURS = ['white', 'blue'].freeze

Примечание: когда мы определяем константы выше, часто мы хотим freeze массива. Это предотвращает последующий (непреднамеренно) другой код, модифицирующий массив, например. добавление нового элемента. После того, как объект заморожен, он больше не может быть изменен.

Ответ 2

Некоторые параметры:

Используя константу:

class Card
  COLOURS = ['white', 'blue', 'black', 'red', 'green', 'yellow'].freeze
end

Lazy загружается с использованием переменной экземпляра класса:

class Card
  def self.colours
    @colours ||= ['white', 'blue', 'black', 'red', 'green', 'yellow'].freeze
  end
end

Если это действительно глобальная константа (избегать глобальных констант такого характера, хотя), вы также можете рассмотреть возможность константу верхнего уровня в config/initializers/my_constants.rb, например.

Ответ 3

Начиная с Rails 4.2, вы можете использовать свойство config.x:

# config/application.rb (or config/custom.rb if you prefer)
config.x.colours.options = %w[white blue black red green]
config.x.colours.default = 'white'

Который будет доступен как:

Rails.configuration.x.colours.options
# => ["white", "blue", "black", "red", "green"]
Rails.configuration.x.colours.default
# => "white"

Еще один способ загрузки пользовательских настроек:

# config/colours.yml
default: &default
  options:
    - white
    - blue
    - black
    - red
    - green
  default: white
development:
  *default
production:
  *default
# config/application.rb
config.colours = config_for(:colours)
Rails.configuration.colours
# => {"options"=>["white", "blue", "black", "red", "green"], "default"=>"white"}
Rails.configuration.colours['default']
# => "white"

В Rails 5 и 6 вы можете использовать объект configuration напрямую для пользовательской конфигурации, в дополнение к config.x. Однако его можно использовать только для не вложенной конфигурации:

# config/application.rb
config.colours = %w[white blue black red green]

Это будет доступно как:

Rails.configuration.colours
# => ["white", "blue", "black", "red", "green"]

Ответ 4

Если константа нужна более чем в одном классе, я всегда добавляю ее в config/initializers/contant.rb во всех кешках (список состояний ниже усечен).

STATES = ['AK', 'AL', ... 'WI', 'WV', 'WY']

Они доступны через приложение, кроме как в коде модели:

    <%= form.label :states, %>
    <%= form.select :states, STATES, {} %>

Чтобы использовать константу в модели, используйте attr_accessor, чтобы сделать константу доступной.

class Customer < ActiveRecord::Base
    attr_accessor :STATES

    validates :state, inclusion: {in: STATES, message: "-- choose a State from the drop down list."}
end

Ответ 5

Для настроек всего приложения и глобальных констант я рекомендую использовать Settingslogic. Эти настройки хранятся в файле YML и доступны из моделей, представлений и контроллеров. Кроме того, вы можете создавать различные настройки для всех ваших сред:

  # app/config/application.yml
  defaults: &defaults
    cool:
      sweet: nested settings
    neat_setting: 24
    awesome_setting: <%= "Did you know 5 + 5 = #{5 + 5}?" %>

    colors: "white blue black red green"

  development:
    <<: *defaults
    neat_setting: 800

  test:
    <<: *defaults

  production:
    <<: *defaults

Где-то в представлении (я предпочитаю вспомогательные методы для такого рода вещей) или в модели, например, вы можете получить массив цветов Settings.colors.split(/\s/). Это очень гибкий. И вам не нужно изобретать велосипед.

Ответ 6

Использовать метод класса:

def self.colours
  ['white', 'red', 'black']
end

Затем Model.colours вернет этот массив. Кроме того, создайте инициализатор и оберните константы в модуле, чтобы избежать конфликтов пространства имен.

Ответ 7

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

module DSL
  module Constants
    MY_CONSTANT = 1
  end
end

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

DSL::Constants::MY_CONSTANT # => 1
MY_CONSTANT # => NameError: uninitialized constant MY_CONSTANT
Object.instance_eval { include DSL::Constants }
MY_CONSTANT # => 1

Ответ 8

Общее место для размещения глобальных констант приложения находится внутри config/application.

module MyApp
  FOO ||= ENV.fetch('FOO', nil)
  BAR ||= %w(one two three)

  class Application < Rails::Application
    config.foo_bar = :baz
  end
end

Ответ 9

Обычно я использую модель/таблицу "lookup" в моей программе rails и использую ее для констант. Это очень полезно, если константы будут отличаться для разных сред. Кроме того, если у вас есть план их расширения, скажите, что вы хотите добавить "желтый" в более позднюю дату, вы можете просто добавить новую строку в таблицу поиска и выполнить ее.

Если вы дадите разрешения администратора для изменения этой таблицы, они не придут к вам для обслуживания.:) СУХОЙ.

Вот как выглядит мой код перехода:

class CreateLookups < ActiveRecord::Migration
  def change
    create_table :lookups do |t|
      t.string :group_key
      t.string :lookup_key
      t.string :lookup_value
      t.timestamps
    end
  end
end

Я использую seeds.rb, чтобы предварительно заполнить его.

Lookup.find_or_create_by_group_key_and_lookup_key_and_lookup_value!(group_key: 'development_COLORS', lookup_key: 'color1', lookup_value: 'red');

Ответ 10

Попробуйте сохранить все константы в одном месте. В моем приложении я создал папку констант внутри инициализаторов следующим образом:

enter image description here

и я обычно сохраняю все константы в этих файлах.

В вашем случае вы можете создать файл в папке констант как colors_constant.rb

colors_constant.rb

enter image description here

Не забыл перезапустить сервер

Ответ 11

Использование константы:

class Card
      Colours = ['White', 'Blue', 'Black', 'Red', 'Green'].freeze
end

Использование переменной экземпляра класса:

class Card

   def self.colours
      @colours ||= ['White', 'Blue', 'Black', 'Red', 'Green'].freeze
   end

end

Ответ 12

Глобальная переменная должна быть объявлена ​​в каталоге config/initializers

COLOURS = %w(white blue black red green)

Ответ 13

В соответствии с вашим состоянием вы также можете определить некоторые переменные среды и получить его с помощью ENV['some-var'] в рубиновом коде, это решение может не поместиться для вас, но я надеюсь, что это может помочь другим.

Пример: вы можете создавать разные файлы .development_env, .production_env, .test_env и загружать их в соответствии с вашими приложениями, проверьте этот ген dotenv- рельсы, которые автоматизируют это для вашего.