Ruby on Rails: где определять глобальные константы? - PullRequest
199 голосов
/ 06 ноября 2010

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

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

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

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

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

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

Ответы [ 12 ]

218 голосов
/ 06 ноября 2010

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

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 массив. Это препятствует тому, чтобы другой код позже (непреднамеренно) изменил массив, например, добавление нового элемента. Как только объект заморожен, он больше не может быть изменен.

66 голосов
/ 06 ноября 2010

Некоторые опции:

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

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

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

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

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

51 голосов
/ 03 декабря 2015

Начиная с 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"]
17 голосов
/ 19 мая 2014

Если константа нужна более чем в одном классе, я помещаю ее в 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
14 голосов
/ 06 ноября 2010

Для настроек всего приложения и глобальных констант я рекомендую использовать 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/) Это очень гибкий. И вам не нужно изобретать велосипед.

7 голосов
/ 06 ноября 2010

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

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

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

3 голосов
/ 29 мая 2016

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

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

  class Application < Rails::Application
    config.foo_bar = :baz
  end
end
3 голосов
/ 08 марта 2016

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

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
2 голосов
/ 10 июля 2018

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

enter image description here

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

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

colors_constant.rb

enter image description here

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

1 голос
/ 27 января 2016

У меня обычно есть модель / таблица поиска в моей программе 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

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

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