it-swarm.com.de

Ruby on Rails: Wo werden globale Konstanten definiert?

Ich fange gerade mit meiner ersten Webapp von Ruby on Rails an. Ich habe eine Reihe verschiedener Modelle, Ansichten, Controller und so weiter. 

Ich möchte einen guten Platz finden, um Definitionen wirklich globaler Konstanten festzulegen, die für meine gesamte App gelten. Sie gelten insbesondere sowohl für die Logik meiner Modelle als auch für die in meinen Ansichten getroffenen Entscheidungen. Ich kann keinen DRY Platz finden, um diese Definitionen dort abzulegen, wo sie sowohl für alle meine Modelle als auch in allen meinen Ansichten verfügbar sind.

Um ein konkretes Beispiel zu nennen, möchte ich eine Konstante COLOURS = ['white', 'blue', 'black', 'red', 'green']. Dies wird überall in den Modellen und Ansichten verwendet. Wo kann ich es nur an einer Stelle definieren, damit es zugänglich ist?

Was ich probiert habe:

  • Konstante Klassenvariablen in der model.rb-Datei, der sie am häufigsten zugeordnet sind, z. B. @@COLOURS = [...]. Aber ich konnte keinen vernünftigen Weg finden, um es zu definieren, so dass ich in meine Ansichten Card.COLOURS schreiben kann, anstatt etwas kludgy wie Card.first.COLOURS.
  • Eine Methode für das Modell, etwa def colours ['white',...] end - dasselbe Problem.
  • Eine Methode in application_helper.rb - das mache ich bisher, aber die Helfer sind nur in Ansichten und nicht in Modellen zugänglich
  • Ich glaube, ich habe vielleicht etwas in application.rb oder environment.rb versucht, aber diese scheinen nicht richtig zu sein (und sie scheinen auch nicht zu funktionieren)

Gibt es einfach keine Möglichkeit, etwas zu definieren, um sowohl von Modellen als auch von Ansichten aus zugänglich zu sein? Ich meine, Modelle und Ansichten sollten getrennt sein, aber in manchen Domänen gibt es Zeiten, in denen sie sich auf dasselbe domänenspezifische Wissen beziehen müssen.

193
AlexC

Wenn Ihr Modell wirklich für die Konstanten "verantwortlich" ist, sollten Sie sie dort angeben. Sie können Klassenmethoden erstellen, um auf sie zuzugreifen, ohne eine neue Objektinstanz zu erstellen:

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

# accessible like this
Card.colours

Alternativ können Sie Klassenvariablen und einen Accessor erstellen. Dies wird jedoch nicht empfohlen, da Klassenvariablen bei Vererbung und in Multithread-Umgebungen überraschend wirken können.

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

# accessible the same as above

Mit den beiden oben genannten Optionen können Sie das zurückgegebene Array bei jedem Aufruf der Zugriffsmethode bei Bedarf ändern. Wenn Sie eine wirklich unveränderliche Konstante haben, können Sie sie auch in der Modellklasse definieren:

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

# accessible as
Card::COLOURS

Sie können auch globale Konstanten erstellen, auf die in einem Initialisierer von überall aus zugegriffen werden kann, wie im folgenden Beispiel. Dies ist wahrscheinlich der beste Ort, wenn Ihre Farben wirklich global sind und in mehr als einem Modellkontext verwendet werden.

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

Hinweis: Wenn wir oben Konstanten definieren, möchten wir oft freeze das Array. Dadurch wird verhindert, dass anderer Code das Array später (unbeabsichtigt) ändert, z. Ein neues Element hinzufügen. Sobald ein Objekt eingefroren ist, kann es nicht mehr geändert werden.

210
Holger Just

Einige Optionen:

Verwenden einer Konstante:

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

Lazy geladen mit Klasseninstanzvariable:

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

Wenn es sich um eine wirklich globale Konstante handelt ( vermeiden Sie globale Konstanten dieser Art jedoch ), könnten Sie auch in Betracht ziehen, __. Eine oberste Konstante in config/initializers/my_constants.rb zu setzen.

65
Zabba

Ab Rails 5.0 können Sie das configuration-Objekt direkt für custom configuration verwenden:

In config/application.rb (oder config/custom.rb, wenn Sie möchten)

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

Es wird erhältlich sein als:

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

Hinweis: Für Version 4.2 müssen Sie die Eigenschaft config.x verwenden:

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

Welche wird verfügbar sein als:

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

Wenn eine Konstante in mehr als einer Klasse benötigt wird, stelle ich sie in config/initializers/contant.rb immer in allen Caps (Liste der Zustände unten ist abgeschnitten).

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

Sie sind in der gesamten Anwendung verfügbar, mit Ausnahme des Modellcodes als solchen:

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

Um die Konstante in einem Modell zu verwenden, verwenden Sie attr_accessor, um die Konstante verfügbar zu machen.

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

Für anwendungsweite Einstellungen und für globale Konstanten empfehle ich die Verwendung von Settingslogic . Diese Einstellungen werden in einer YML-Datei gespeichert und können über Modelle, Ansichten und Controller aufgerufen werden. Noch mehr .. Sie können verschiedene Einstellungen für alle Ihre Umgebungen erstellen:

  # 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

Irgendwo in der Ansicht (ich bevorzuge Helfer-Methoden für solche Sachen) oder in einem Modell können Sie zum Beispiel eine Reihe von Farben Settings.colors.split(/\s/) bekommen. Es ist sehr flexibel. Und Sie müssen kein Fahrrad erfinden.

14
Voldy

Verwenden Sie eine Klassenmethode:

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

Dann wird Model.colours dieses Array zurückgeben. Alternativ können Sie einen Initialisierer erstellen und die Konstanten in ein Modul einschließen, um Namensraumkonflikte zu vermeiden.

7
Steve Ross

Eine weitere Option, wenn Sie Ihre Konstanten an einer Stelle definieren möchten:

module DSL
  module Constants
    MY_CONSTANT = 1
  end
end

Machen Sie sie dennoch global sichtbar, ohne auf sie qualifiziert zugreifen zu müssen:

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

Ein allgemeiner Ort für anwendungsweite globale Konstanten ist in 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

Versuchen Sie, alle an einer Stelle konstant zu halten. In meiner Anwendung habe ich Konstantenordner in den Initialisierern wie folgt erstellt:

 enter image description here

und ich halte normalerweise alle in diesen Dateien konstant.

In Ihrem Fall können Sie unter colors_constant.rb eine Datei im Konstantenordner anlegen.

colors_constant.rb

 enter image description here

Vergiss nicht, Server neu zu starten 

1
Ghanshyam Anand

Ich habe in meinem Rails-Programm normalerweise ein 'Lookup'-Modell/eine Tabelle und verwende es für die Konstanten. Dies ist sehr nützlich, wenn die Konstanten für verschiedene Umgebungen unterschiedlich sind. Wenn Sie einen Plan haben, um sie zu erweitern, sagen Sie, dass Sie zu einem späteren Zeitpunkt 'gelb' hinzufügen möchten, können Sie der Suchtabelle einfach eine neue Zeile hinzufügen und fertig sein.

Wenn Sie dem Administrator Berechtigungen zum Ändern dieser Tabelle erteilen, werden diese nicht zur Wartung an Sie gesendet. :) TROCKEN.

So sieht mein Migrationscode aus:

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

Ich benutze Seeds.RB, um es vorab zu bevölkern.

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

Je nach Ihrer Bedingung können Sie auch einige Umgebungsvariablen definieren und diese über ENV['some-var'] in Ruby-Code abrufen. Diese Lösung ist möglicherweise nicht für Sie geeignet, aber ich hoffe, dass sie anderen helfen kann. 

Beispiel: Sie können verschiedene Dateien .development_env, .production_env, .test_env erstellen und sie entsprechend Ihren Anwendungsumgebungen laden. Überprüfen Sie hierzu diese gen dotenv-Rails , die dies für Ihre.

0
fangxing

Die globale Variable sollte im Verzeichnis config/initializers deklariert werden

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