web-dev-qa-db-fra.com

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

Je commence tout juste à utiliser ma première application Web Ruby on Rails. J'ai un tas de différents modèles, vues, contrôleurs, etc. 

Je souhaite trouver le bon endroit pour coller des définitions de constantes véritablement globales, qui s'appliquent à l'ensemble de mon application. En particulier, ils s’appliquent à la fois à la logique de mes modèles et aux décisions prises à mon avis. Je ne trouve aucun DRY endroit pour placer ces définitions là où elles sont disponibles à la fois pour tous mes modèles et également pour tous mes points de vue.

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

Ce que j'ai essayé

  • Variables de classe constantes dans le fichier model.rb auquel elles sont le plus associées, telles que @@COLOURS = [...]. Mais je ne pouvais pas trouver un moyen sain de le définir pour pouvoir écrire dans mon point de vue Card.COLOURS plutôt que quelque chose de similaire à 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 application.rb ou environment.rb, mais ceux-ci ne semblent pas vraiment bons (et ils ne semblent pas non plus fonctionner)

N'y a-t-il aucun moyen 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 points de vue doivent être séparés, mais dans certains domaines, il sera parfois nécessaire de faire référence à la même connaissance spécifique à un domaine?

193
AlexC

Si votre modèle est vraiment "responsable" des constantes, vous devriez 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

Vous pouvez également créer des variables de classe et un accesseur. Cela est toutefois déconseillé, car les variables de classe peuvent sembler surprenantes avec l'héritage et les environnements multi-thread.

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

# accessible the same as above

Les deux options ci-dessus vous permettent de modifier le tableau renvoyé à chaque appel de la méthode d'accès, si nécessaire. Si vous avez une constante vraiment non modifiable, vous pouvez également la définir dans 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 accessibles de partout dans un initialiseur, comme dans l'exemple suivant. C’est probablement le meilleur endroit, si vos couleurs sont vraiment globales et utilisées dans plusieurs contextes de modèle.

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

Remarque: lorsque nous définissons les constantes ci-dessus, nous voulons souvent freeze le tableau. Cela empêche tout autre code de modifier ultérieurement (par inadvertance) le tableau, par ex. ajout d'un nouvel élément. Une fois qu'un objet est gelé, il ne peut plus être changé.

210
Holger Just

Quelques options:

En utilisant une constante:

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

Chargement paresseux à l'aide d'une variable d'instance de classe:

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

S'il s'agit d'une constante véritablement globale ( évitez les constantes globales de cette nature, bien que ), vous pouvez également envisager de placer Une constante de niveau supérieur dans config/initializers/my_constants.rb, par exemple.

65
Zabba

A 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 tant que:

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

Remarque: Pour la version 4.2, vous devez utiliser la propriété config.x :

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

Qui sera disponible en tant que:

Rails.configuration.x.colours # => ["white", "blue", "black", "red", "green"]
48
Halil Özgür

Si une constante est nécessaire dans plusieurs classes, je la mets dans config/initializers/contant.rb toujours en majuscules (la liste des états ci-dessous est tronquée).

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

Ils sont disponibles via l'application, sauf dans le code du 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 la rendre disponible.

class Customer < ActiveRecord::Base
    attr_accessor :STATES

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

Pour les paramètres d'application et pour les constantes globales, il est recommandé d'utiliser Settingslogic . Ces paramètres sont stockés dans un fichier YML et sont accessibles à partir de modèles, vues et 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'assistance pour ce genre de choses) ou dans un modèle, vous pouvez obtenir, par exemple, un tableau de couleurs Settings.colors.split(/\s/). C'est très flexible. Et vous n'avez pas besoin d'inventer un vélo.

14
Voldy

Utilisez une méthode de classe:

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

Alors Model.colours retournera ce tableau. Vous pouvez également créer un initialiseur et envelopper les constantes dans un module pour éviter les conflits d'espaces de noms.

7
Steve Ross

Une autre option, si vous souhaitez définir vos constantes à un endroit:

module DSL
  module Constants
    MY_CONSTANT = 1
  end
end

Mais restez néanmoins visibles au niveau mondial 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
3
wincent

Un emplacement commun pour mettre les constantes globales à l'échelle 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
Dennis

Essayez de garder tous les constants au même endroit. Dans mon application, j'ai créé le dossier des constantes dans les initialiseurs comme suit:

 enter image description here

et je garde habituellement tout constant dans ces fichiers.

Dans votre cas, vous pouvez créer un fichier sous le dossier des constantes sous la forme colors_constant.rb

colors_constant.rb

 enter image description here

N'oubliez pas de redémarrer le serveur 

1
Ghanshyam Anand

J'ai généralement un modèle/une table de recherche dans mon programme Rails et je l'utilise pour les constantes. Il est très utile que les constantes soient différentes pour différents environnements. De plus, si vous avez l'intention de les étendre, par exemple si vous souhaitez ajouter «jaune» à une date ultérieure, vous pouvez simplement ajouter une nouvelle ligne à la table de recherche et en finir.

Si vous autorisez l'administrateur à modifier ce tableau, il ne vous contactera pas pour des raisons de maintenance. :) 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 seeds.rb pour le pré-peupler.

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

Selon votre condition, vous pouvez également définir certaines variables d'environnement et les récupérer via ENV['some-var'] dans le code Ruby. Cette solution peut ne pas vous convenir, mais j'espère que cela pourra aider les autres. 

Exemple: vous pouvez créer différents fichiers .development_env, .production_env, .test_env et les charger en fonction de votre environnement d’application, cochez cette commande gen dotenv-Rails qui l’automatise automatiquement.

0
fangxing

La variable globale doit être déclarée dans le répertoire config/initializers

COLOURS = %w(white blue black red green)
0
Tam Dc