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 vuesCard.COLOURS
plutôt que quelque chose de kludgy commeCard.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?
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é.
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.
à 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"]
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
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.
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.
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
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
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');
la variable globale doit être déclarée dans config/initializers
directory
COLOURS = %w(white blue black red green)
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.
essayer de garder tout constant à un endroit, dans mon application j'ai créé le dossier constantes à l'intérieur des initialiseurs comme suit:
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
N'oubliez pas de redémarrer le serveur