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

Je commence juste avec ma première webapp Ruby on Rails. J’ai un tas de différents modèles, vues, contrôleurs, etc.

Je veux trouver un bon endroit pour coller les définitions de constantes véritablement globales, qui s’appliquent à l’ensemble de mon application. En particulier, elles s’appliquent à la fois dans la logique de mes modèles et dans les décisions sockets dans mes vues. Je ne trouve aucun endroit SEC pour mettre ces définitions là où elles sont disponibles à la fois dans tous mes modèles et dans toutes mes vues.

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

Ce que j’ai essayé:

  • Les variables de classe constante dans le fichier model.rb auquel elles sont le plus associées, telles que @@COLOURS = [...] . Mais je ne pouvais pas trouver un moyen sensé de le définir pour pouvoir écrire dans mes vues Card.COLOURS plutôt que quelque chose 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’ici, mais les helpers ne sont accessibles que dans les vues, pas dans les modèles
  • Je pense que je pourrais avoir essayé quelque chose dans application.rb ou environment.rb, mais ceux-ci ne semblent pas vraiment corrects (et ils ne semblent pas fonctionner non plus)

N’y a-t-il aucun moyen de définir quoi que ce soit accessible à la fois à partir de modèles et de vues? Je veux dire, je sais que les modèles et les vues doivent être séparés, mais dans certains domaines, il faudra sûrement parfois se référer aux mêmes connaissances spécifiques à un domaine?

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 de nouvelle instance d’object:

 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 cependant déconseillé car les variables de classe peuvent surprendre avec l'inheritance et dans 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 de l'accesseur si nécessaire. Si vous avez une constante vraiment immuable, vous pouvez également la définir dans la classe du modèle:

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

Vous pouvez également créer des constantes globales accessibles partout dans l'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èles.

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

Note: quand on définit les constantes ci-dessus, on veut souvent freeze le tableau. Cela empêche les autres codes de modifier ultérieurement (par inadvertance) le tableau en ajoutant par exemple un nouvel élément. Une fois qu'un object est gelé, il ne peut plus être modifié.

Quelques options:

En utilisant une constante:

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

Lazy chargé à l’aide de la 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 ( évitez les constantes globales de cette nature, cependant ), vous pouvez également envisager de mettre une constante de niveau supérieur dans config/initializers/my_constants.rb par exemple.

A partir de Rails 5.0, vous pouvez utiliser l’object de configuration directement pour la 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 comme:

 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 comme:

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

Si une constante est nécessaire dans plusieurs classes, je la place 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 dans l’application, sauf dans le code 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 

Pour les parameters d’application et pour les constantes globales, il est recommandé d’utiliser Settingslogic . Ces parameters sont stockés dans un fichier YML et sont accessibles à partir de modèles, de vues et de contrôleurs. Encore plus .. vous pouvez créer différents parameters 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, 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.

Utilisez une méthode de classe:

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

Model.colours renvoie alors ce tableau. Vous pouvez également créer un initialiseur et envelopper les constantes dans un module pour éviter les conflits d’espace de noms.

Un endroit commun pour placer des constantes globales à l’échelle de l’application se trouve dans config/application .

 module MyApp FOO ||= ENV.fetch('FOO', nil) BAR ||= %w(one two three) class Application < Rails::Application config.foo_bar = :baz end end 

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

 module DSL module Constants MY_CONSTANT = 1 end end 

Mais toujours les rendre globalement visibles sans avoir à y accéder de manière entièrement qualifiée:

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

J’ai généralement un modèle / table de consultation dans mon programme de rails et je l’utilise pour les constantes. Il est très utile que les constantes soient différentes selon les environnements. De plus, si vous envisagez de les étendre, par exemple si vous souhaitez append «jaune» à une date ultérieure, vous pouvez simplement append une nouvelle ligne à la table de recherche et en terminer avec celle-ci.

Si vous autorisez l’administrateur à modifier cette table, ils ne vous contacteront pas pour 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é-remplir.

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

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

 COLOURS = %w(white blue black red green) 

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

Exemple: vous pouvez créer différents fichiers .development_env , .production_env , .test_env et les charger en fonction de vos environnements applicatifs, vérifiez cette gen dotenv-rails qui automatise cela pour votre.

Essayez de garder tous les constants à un seul endroit. Dans mon application, j’ai créé un dossier de constantes dans les initialiseurs comme suit:

entrer la description de l'image ici

et je garde généralement toutes les constantes dans ces fichiers.

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

colors_constant.rb

entrer la description de l'image ici

N’oubliez pas de redémarrer le serveur