Ruby on Rails: где определить глобальные константы?
Я только начинаю с моего первого Ruby on Rails webapp. У меня есть куча разных моделей, представлений, контроллеров и так далее.
Я хочу найти хорошее место, чтобы придерживаться определения действительно глобальных констант, которые применяются во всем моем приложении. В частности, они применимы как в логике моих моделей, так и в решениях, принимаемых на мой взгляд. Я не могу найти сухого места, чтобы поместить эти определения, где они доступны как для все мои модели, а также в все мои взгляды.
чтобы взять конкретный пример, я хочу константу COLOURS = ['white', 'blue', 'black', 'red', 'green']. Это используется повсюду, как в моделях, так и в представлениях. Где я могу определить его только в одном месте, чтобы он был доступен?
что я пробовал:
- постоянные переменные класса в модели.rb-файл, с которым они больше всего связаны, например
@@COLOURS = [...]. Но я не мог найти разумный способ определить его, чтобы я мог писать в своих представленияхCard.COLOURSа не что-то запутано какCard.first.COLOURS. - метод на модели, что-то вроде
def colours ['white',...] end- та же проблема. - метод в application_helper.rb-это то, что я делаю до сих пор, но помощники доступны только в представлениях, а не в моделях
- я думаю, что я мог бы попробовать что-то в приложении.РБ или окружающая среда.rb, но они действительно не кажутся правильными (и они, похоже, тоже не работают)
просто нет способа определить что-либо, чтобы быть доступным как из модели и представления? Я имею в виду, что я знаю, что модели и представления должны быть отдельными, но, конечно, в некоторых доменах будут времена, когда им нужно будет ссылаться на одно и то же доменное знание?
12 ответов:
если ваша модель действительно "отвечает" за константы, вы должны вставить их туда. Вы можете создать методы класса могут обращаться к ним без создания нового экземпляра объекта:
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два варианта выше позволяют изменить возвращаемый массив на каждом вызов метода доступа, если требуется. Если у вас есть true действительно неизменяемая константа, вы также можете определить ее в классе модели:
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матрица. Это предотвращает последующее (непреднамеренное) изменение массива другим кодом, например, путем добавления нового элемента. После того, как объект заморожен, он больше не может быть изменен.
варианты:
используя константу:
class Card COLOURS = ['white', 'blue', 'black', 'red', 'green', 'yellow'].freeze endLazy загружается с помощью переменной экземпляра класса:
class Card def self.colours @colours ||= ['white', 'blue', 'black', 'red', 'green', 'yellow'].freeze end endЕсли это действительно глобальная константа (избегайте глобальных констант такого рода, хотя), вы также можете рассмотреть вопрос о размещении константа верхнего уровня в
config/initializers/my_constants.rbнапример.
начиная с Rails 5.0, вы можете использовать
configurationобъект непосредственно для конфигурации:на
config/application.rb(илиconfig/custom.rbесли вы предпочитаете)config.colours = %w(white blue black red green)он будет доступен как:
Rails.configuration.colours # => ["white", "blue", "black", "red", "green"]
Примечание: для версии 4.2, вы должны использовать
config.xсвойства:config.x.colours = %w(white blue black red green)который будет доступен как:
Rails.configuration.x.colours # => ["white", "blue", "black", "red", "green"]
Если константа нужна более чем в одном классе, я помещаю ее в 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
для общих настроек приложения и для глобальных констант я рекомендую использовать Settingslogic. Эти настройки хранятся в файле YML и могут быть доступны из моделей, представлений и контроллеров. Еще больше.. вы можете создать различные настройки для всех ваших сред:
# app/config/application.yml defaults: &defaults cool: saweet: 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/). Он очень гибкий. И вам не нужно изобретать велосипед.
использовать метод класса:
def self.colours ['white', 'red', 'black'] endзатем
Model.coloursвозвращает массив. Кроме того, создайте инициализатор и оберните константы в модуль, чтобы избежать конфликтов пространств имен.
общее место для размещения глобальные константы для всего приложения внутри
config/application.module MyApp FOO ||= ENV.fetch('FOO', nil) BAR ||= %w(one two three) class Application < Rails::Application config.foo_bar = :baz end end
другой вариант, если вы хотите определить свои константы в одном месте:
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
обычно у меня есть модель/таблица "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Я использую семена.РБ, чтобы предварительно заполнить его.
Lookup.find_or_create_by_group_key_and_lookup_key_and_lookup_value!(group_key: 'development_COLORS', lookup_key: 'color1', lookup_value: 'red');
глобальная переменная должна быть объявлена в
config/initializersкаталогCOLOURS = %w(white blue black red green)
в соответствии с вашим условием, вы также можете определить некоторые переменные среды, и получить его через
ENV['some-var']в коде Ruby, это решение может не подойти для вас, но я надеюсь, что это может помочь другим.пример: вы можете создавать различные файлы
.development_env,.production_env,.test_envи загрузите его в соответствии с вашими средами приложений, проверьте это поколение dotenv-rails которые автоматизируют это для вашего.
попробуйте сохранить все константы в одном месте, в моем приложении я создал папку константы внутри инициализаторов следующим образом:
и я обычно держу все в этих файлах.
в вашем случае вы можете создать файл в папке константы как
colors_constant.rbcolors_constant.РБ
не забудьте перезагрузить сервер


Comments