Programing

Ruby on Rails : 전역 상수를 정의 할 위치는?

lottogame 2020. 5. 7. 07:55
반응형

Ruby on Rails : 전역 상수를 정의 할 위치는?


첫 번째 Ruby on Rails webapp을 시작했습니다. 다양한 모델, 뷰, 컨트롤러 등이 있습니다.

전체 응용 프로그램에 적용되는 진정한 글로벌 상수의 정의를 고수 할 수있는 좋은 장소를 찾고 싶습니다. 특히, 그들은 내 모델의 논리와 내 견해에서 내린 결정 모두에 적용됩니다. 이 정의를 모든 모델과 모든 뷰에서 사용할 수있는 곳에 DRY 장소를 찾을 수 없습니다 .

구체적인 예를 들어, 상수를 원합니다 COLOURS = ['white', 'blue', 'black', 'red', 'green']. 이것은 모델과 뷰 모두에서 모든 곳에서 사용됩니다. 한 곳에서 액세스 할 수 있도록 어디에서 정의 할 수 있습니까?

내가 시도한 것 :

  • 그들은 대부분 같은과 관련있는 것을 model.rb 파일 정수 클래스 변수 @@COLOURS = [...]. 그러나 나는 그것을 정의하는 깔끔한 방법을 찾지 못하여 Card.COLOURS과감한 것보다는 내 견해를 쓸 수 Card.first.COLOURS있었습니다.
  • def colours ['white',...] end같은 문제 와 같은 모델의 방법 .
  • application_helper.rb의 메소드-지금까지 내가하고있는 일이지만 도우미는 모델이 아닌보기에서만 액세스 할 수 있습니다
  • application.rb 또는 environment.rb에서 무언가를 시도했을 수도 있지만 실제로는 올바르지 않습니다 (그리고 작동하지 않는 것 같습니다)

모델과 뷰에서 액세스 할 수있는 항목을 정의 할 방법이 없습니까? 내 말은, 모델과 뷰가 분리되어야한다는 것을 알고 있지만, 어떤 도메인에서는 반드시 동일한 도메인 별 지식을 참조해야하는 경우가 있습니까?


상수에 대해 모델이 실제로 "책임"인 경우에는 거기에 고정시켜야합니다. 새 객체 인스턴스를 만들지 않고 클래스 메서드를 만들어 액세스 할 수 있습니다.

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

# accessible like this
Card.colours

또는 클래스 변수와 접근자를 만들 수 있습니다. 그러나 클래스 변수가 상속 및 멀티 스레드 환경에서 놀라운 역할을 할 수 있으므로 권장하지 않습니다.

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

# accessible the same as above

위의 두 옵션을 사용하면 필요한 경우 접근 자 메서드를 호출 할 때마다 반환 된 배열을 변경할 수 있습니다. 진정으로 변경 불가능한 상수가있는 경우 모델 클래스에서 정의 할 수도 있습니다.

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

# accessible as
Card::COLOURS

다음 예제와 같이 초기화 프로그램의 모든 곳에서 액세스 할 수있는 전역 상수를 만들 수도 있습니다. 색상이 실제로 전체적이며 둘 이상의 모델 컨텍스트에서 사용되는 경우이 위치가 가장 적합합니다.

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

참고 : 상수를 위에서 정의 할 때 종종 freeze배열을 원합니다 . 그러면 다른 요소가 나중에 실수로 새 요소를 추가하여 배열을 수정하는 것을 방지 할 수 있습니다. 개체가 고정되면 더 이상 변경할 수 없습니다.


일부 옵션 :

상수 사용하기 :

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

클래스 인스턴스 변수를 사용하여 지연로드 됨 :

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

그것이 진정한 글로벌 상수라면 ( 그러나이 성격의 글로벌 상수를 피하십시오 ), config/initializers/my_constants.rb예를 들어 최상위 상수를 넣는 것도 고려할 수 있습니다 .


Rails 4.2부터는 다음과 같은 config.x속성을 사용할 수 있습니다 .

# config/application.rb (or config/custom.rb if you prefer)
config.x.colours.options = %w[white blue black red green]
config.x.colours.default = 'white'

다음과 같이 사용할 수 있습니다.

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

Another method of loading custom config:

# config/colours.yml
default: &default
  options:
    - white
    - blue
    - black
    - red
    - green
  default: white
development:
  *default
production:
  *default
# config/application.rb
config.colours = config_for(:colours)
Rails.configuration.colours
# => {"options"=>["white", "blue", "black", "red", "green"], "default"=>"white"}
Rails.configuration.colours['default']
# => "white"

In Rails 5 & 6, you can use the configuration object directly for custom configuration, in addition to config.x. However, it can only be used for non-nested configuration:

# config/application.rb
config.colours = %w[white blue black red green]

It will be available as:

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

If a constant is needed in more than one class, I put it in config/initializers/contant.rb always in all caps (list of states below is truncated).

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

They are available through out the application except in model code as such:

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

To use the constant in a model, use attr_accessor to make the constant available.

class Customer < ActiveRecord::Base
    attr_accessor :STATES

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

For application-wide settings and for global constants I recommend to use Settingslogic. This settings are stored in YML file and can be accessed from models, views and controllers. Furthermore, you can create different settings for all your environments:

  # app/config/application.yml
  defaults: &defaults
    cool:
      sweet: 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

Somewhere in the view (I prefer helper methods for such kind of stuff) or in a model you can get, for ex., array of colors Settings.colors.split(/\s/). It's very flexible. And you don't need to invent a bike.


Use a class method:

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

Then Model.colours will return that array. Alternatively, create an initializer and wrap the constants in a module to avoid namespace conflicts.


Another option, if you want to define your constants in one place:

module DSL
  module Constants
    MY_CONSTANT = 1
  end
end

But still make them globally visible without having to access them in fully qualified way:

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

A common place to put application-wide global constants is inside config/application.

module MyApp
  FOO ||= ENV.fetch('FOO', nil)
  BAR ||= %w(one two three)

  class Application < Rails::Application
    config.foo_bar = :baz
  end
end

I typically have a 'lookup' model/table in my rails program and use it for the constants. It is very useful if the constants are going to be different for different environments. In addition, if you have a plan to extend them, say you want to add 'yellow' on a later date, you could simply add a new row to the lookup table and be done with it.

If you give the admin permissions to modify this table, they will not come to you for maintenance. :) DRY.

Here is how my migration code looks like:

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

I use seeds.rb to pre-populate it.

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

Try to keep all constant at one place, In my application I have created constants folder inside initializers as follows:

enter image description here

and I usually keep all constant in these files.

In your case you can create file under constants folder as colors_constant.rb

colors_constant.rb

enter image description here

Don't forgot to restart server


The global variable should be declare in config/initializers directory

COLOURS = %w(white blue black red green)

According your condition, you can also define some environmental variables, and fetch it via ENV['some-var'] in ruby code, this solution may not fit for you, but I hope it may help others.

Example: you can create different files .development_env, .production_env, .test_env and load it according your application environments, check this gen dotenv-rails which automate this for your.

참고URL : https://stackoverflow.com/questions/4110866/ruby-on-rails-where-to-define-global-constants

반응형