5
votes

I've defined custom configuration variables in my rails app (APP_CONFIG hash). Ok, now how can I use these variables in my models? Directly calling APP_CONFIG['variable'] in models its a not rails way! For example I can use these models without Rails environment. Then APP_CONFIG not be defined.

ATM I use model observer and assign global config variables with instance variables, like this:

def after_initialize model
  Mongoid.observers.disable :all do
    model.user_id = APP_CONFIG['user_id'])
    model.variable = User.find(model.user_id).variable
  end
end

But this solution looks like a monkey patch. There is better way?

Or I should keep it simplest and can just define APP_CONFIG hash in new app (not Rails app)?

3

3 Answers

1
votes

I'd use dependency injection. If you have an object that needs various config values, you could inject the config object through the constructor:

class Something
  def initialize(config = APP_CONFIG)
    @config = config
  end
end

And if the config is only needed for a single method, simply pass it to the method:

def something(config = APP_CONFIG)
  # do something
end

Ruby evaluates parameters when the method is called. The default value allows you to use your config object in development/production without having to manually pass it to the methods and to use a stub instead of the actual config in your tests.

Instead of defining another global variable/constant, you could also use the Rails config instead:

def something(config = Rails.config)
  # do something
end
0
votes

/config/config.yml

defaults: &defaults
  user_id :100

development:
  <<: *defaults

test:
  <<: *defaults

production:
  <<: *defaults

/config/initializers/app_config.rb

APP_CONFIG = YAML.load_file("#{Rails.root}/config/config.yml")[Rails.env]

You can now use APP_CONFIG['user_id'] in model

0
votes

Use :before_create to keep the code localized to your model:

class MyModel < ActiveRecord::Base

  before_create :set_config

  private

  def set_config
    self.app_config = APP_CONFIG
  end
end

Or, as an alternative, you can use ActiveSupport::Concern, which is a very clean way of creating a module that you could nicely reuse in N models:

class MyModel < ActiveRecord::Base    
  include AppConfig     
end

module AppConfig
    extend ActiveSupport::Concern

    included do
       #...
    end

    module ClassMethods
       #...
    end

    def app_config
      APP_CONFIG
    end
end