Ruby on Rails: où définir les constantes globales?

Je ne fais que commencer avec mon premier Ruby on Rails webapp. J'ai un tas de différents modèles, vues, contrôleurs, et ainsi de suite.

je veux trouver un bon endroit pour coller des définitions de constantes vraiment globales, qui s'appliquent à travers toute mon application. En particulier, elles s'appliquent à la fois à la logique de mes modèles et aux décisions prises dans mes opinions. Je ne trouve aucun endroit sec pour mettre ces définitions là où elles sont disponibles à la fois à tous mes modèles et aussi dans tous mes points de vue.

pour prendre un exemple précis, je veux une constante COLOURS = ['white', 'blue', 'black', 'red', 'green'] . Ceci est utilisé partout, aussi bien dans les modèles que dans les vues. Où puis-je le définir en un seul endroit pour qu'il soit accessible?

Ce que j'ai essayé:

  • Constante de classe de variables dans le modèle.fichier rb auquel ils sont le plus associés, comme @@COLOURS = [...] . Mais je n'ai pas pu trouver une façon sensée de le définir pour que je puisse écrivez dans mes vues Card.COLOURS plutôt que quelque chose de kludgy comme Card.first.COLOURS .
  • Une méthode sur le modèle, quelque chose comme def colours ['white',...] end - même problème.
  • Une méthode dans application_helper.rb - c'est ce que je fais jusqu'à présent, mais les aides ne sont accessibles que dans les vues, pas dans les modèles
  • je pense que j'ai peut-être essayé quelque chose dans l'application.rb ou environnement.rb, mais ceux-ci ne semblent pas vraiment bien (et ils ne semblent pas fonctionner soit)

est-il tout simplement impossible de définir quoi que ce soit pour être accessible à la fois à partir de modèles et de vues? Je veux dire, je sais que les modèles et les vues devraient être séparés, mais sûrement dans certains domaines il y aura des moments où ils devront se référer à la même connaissance spécifique du domaine?

187
demandé sur AlexC 2010-11-06 02:06:37

12 réponses

si votre modèle est vraiment" responsable " des constantes, vous devez les y coller. Vous pouvez créer des méthodes de classe pour y accéder sans créer une nouvelle instance d'objet:

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

# accessible like this
Card.colours

alternativement, vous pouvez créer des variables de classe et un accessor. Ceci est cependant découragé car les variables de classe peuvent agir un peu surprenant avec l'héritage et dans les environnements à plusieurs fils.

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

# accessible the same as above

Les deux options ci-dessus vous permettent de changer le tableau retourné sur chaque invocation de la méthode accessor si nécessaire. Si vous avez vrai une constante vraiment immuable, vous pouvez également la définir sur la classe de modèle:

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

# accessible as
Card::COLOURS

, Vous pouvez également créer des constantes globales qui sont accessibles de partout dans un initialiseur comme dans l'exemple suivant. C'est probablement le meilleur endroit, si vos couleurs sont vraiment mondiale et utilisé dans plus d'un contexte de modèle.

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

Note: lorsque nous définissons les constantes ci-dessus, souvent nous voulons freeze le tableau. Cela empêche un autre code de modifier plus tard (par inadvertance) le tableau en ajoutant par exemple un nouvel élément. Une fois qu'un objet est gelé, il ne peut plus être modifié.

205
répondu Holger Just 2016-05-29 11:29:05

quelques options:

utilisant une constante:

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

Paresseux chargé à l'aide de variable d'instance de classe:

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

si c'est une constante vraiment globale ( éviter les constantes globales de cette nature, bien que ), vous pouvez également envisager de mettre une constante de haut niveau dans config/initializers/my_constants.rb par exemple.

64
répondu Zabba 2016-05-30 07:14:02

à partir de Rails 5.0, vous pouvez utiliser l'objet configuration directement pour configuration personnalisée :

dans config/application.rb (ou config/custom.rb si vous préférez)

config.colours = %w(white blue black red green)

, Il sera disponible en:

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

Note: pour la version 4.2, vous devez utiliser la config.x propriété:

config.x.colours = %w(white blue black red green)

qui sera disponible en tant que:

Rails.configuration.x.colours # => ["white", "blue", "black", "red", "green"]
44
répondu Halil Özgür 2016-07-19 17:16:03

si une constante est nécessaire dans plus d'une classe, je la mets dans config/initializers/contant.rb toujours dans tous les cas (la liste des états ci-dessous est tronquée).

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

ils sont disponibles dans toute l'application sauf dans le code de modèle en tant que tel:

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

pour utiliser la constante dans un modèle, utilisez attr_accessor pour rendre la constante disponible.

class Customer < ActiveRecord::Base
    attr_accessor :STATES

    validates :state, inclusion: {in: STATES, message: "-- choose a State from the drop down list."}
end
16
répondu Hank Snow 2014-05-18 20:36:36

pour les paramètres d'application et pour les constantes globales je recommande d'utiliser Settinglogic . Ces paramètres sont stockés dans le fichier YML et peuvent être consultés à partir des modèles, des vues et des contrôleurs. Encore plus.. vous pouvez créer différents paramètres pour tous vos environnements:

  # 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

quelque part dans la vue (je préfère les méthodes d'aide pour ce genre de choses) ou dans un modèle que vous pouvez obtenir, par exemple., tableau de couleurs Settings.colors.split(/\s/) . C'est très flexible. Et vous n'avez pas besoin d'inventer un vélo.

14
répondu Voldy 2010-11-05 23:50:58

utiliser une méthode de classe:

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

puis Model.colours retournera ce tableau. Alternativement, créez un initialiseur et enveloppez les constantes dans un module pour éviter les conflits d'espace de noms.

7
répondu Steve Ross 2010-11-06 03:15:10

un endroit commun pour mettre les constantes mondiales de l'application est à l'intérieur de 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
répondu Dennis 2016-05-29 13:10:03

une autre option, si vous voulez définir vos constantes à un endroit:

module DSL
  module Constants
    MY_CONSTANT = 1
  end
end

mais encore les rendre globalement visibles sans avoir à y accéder de manière pleinement qualifiée:

DSL::Constants::MY_CONSTANT # => 1
MY_CONSTANT # => NameError: uninitialized constant MY_CONSTANT
Object.instance_eval { include DSL::Constants }
MY_CONSTANT # => 1
2
répondu wincent 2016-03-08 01:43:16

j'ai typiquement un modèle/tableau 'lookup' dans mon programme rails et je l'utilise pour les constantes. C'est très utile si les constantes sont différentes pour des environnements différents. En outre, si vous avez un plan, de les prolonger, de dire que vous voulez ajouter 'jaune' sur une date ultérieure, vous pouvez simplement ajouter une nouvelle ligne à la table de recherche et être fait avec elle.

Si vous donnez les autorisations d'administrateur pour modifier ce tableau, ils ne viendront pas à vous pour l'entretien. :) SEC.

voici à quoi ressemble mon code de migration:

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

j'utilise des graines.rb pour pré-remplir.

Lookup.find_or_create_by_group_key_and_lookup_key_and_lookup_value!(group_key: 'development_COLORS', lookup_key: 'color1', lookup_value: 'red');
1
répondu SriSri 2016-01-27 11:25:23

la variable globale doit être déclarée dans config/initializers directory

COLOURS = %w(white blue black red green)
0
répondu Tam Dc 2017-04-11 04:03:55

selon votre condition, vous pouvez également définir certaines variables d'environnement, et fetch it via ENV['some-var'] dans ruby code, Cette solution peut ne pas convenir pour vous, mais j'espère qu'il peut aider d'autres.

exemple: vous pouvez créer des fichiers différents .development_env , .production_env , .test_env et le charger selon vos environnements d'application, vérifiez ce gen dotenv-rails qui automatisent cela pour votre.

0
répondu fangxing 2017-12-03 04:32:43

essayer de garder tout constant à un endroit, dans mon application j'ai créé le dossier constantes à l'intérieur des initialiseurs comme suit:

enter image description here

et je garde tout constant dans ces fichiers.

dans votre cas, vous pouvez créer un fichier sous le dossier constantes comme colors_constant.rb

colors_constant.rb

enter image description here

N'oubliez pas de redémarrer le serveur

0
répondu Ghanshyam Anand 2018-07-10 08:12:49