Reputation: 1701
I'm creating a model called Configuration and I have the following code and I want to make it more dynamic by using metaprogramming.
In a table on the database for Configuration model I have the following data.
---------------------------------------------------------
variable_name as string | value in text
|
company_name | MyCompany
welcome_text | Welcome to MyCompany's App!
email_order_text | You've just created an account with MyCompany.
year_since | 2012
----------------------------------------------------------
class Configuration < ActiveRecord::Base
#nothing here yet
end
----------------------------------------------------------
Currently, the only way to access the company_name is to do the following in rails console:
configuration_company_name = Configuration.find_by_variable_name("company_name")
configuration_company_name.company_name
> "MyCompany"
I think this is an unacceptable way to do things. First, it will access the database everytime someone checks for the company's name. I think if I could load it when the app starts and doesn't have to access it again because it's in the memory, then it would be better. How can I do something more dynamic so I could access the value "MyCompany" like this.
Configuration.company_name
> "MyCompany"
The reason to do this is to give allow fast customization of the application.
Upvotes: 1
Views: 806
Reputation: 64363
class Configuration < ActiveRecord::Base
# loads all the configuration variables to an in-memory
# static hash during the first access.
def self.[](n)
@config ||= {}.tap { |h| Configuration.all.each{ h[variable_name] = c.value}}
@config[n]
end
end
Now you can access your configuration as :
Configuration["company_name"]
If you a large number of configuration parameters, it might be beneficial to pre-load the cache by accessing a configuration parameter in an initializer file. If you have 1000s of configuration variables you might have to consider migrating the cache to memcached
etc.
If you want to access the configuration parameter as a class method:
class Configuration < ActiveRecord::Base
klass = class << self; self; end
Configuration.all.each{|c| klass.send(:define_method, c.variable_name){c.value}}
end
Now you can access the parameter as follows:
Configuration.company_name
Upvotes: 5
Reputation: 5914
We can move these constant values into a yml
file, when the server starts load them into a variable and access it whenever needed.
Upvotes: 0
Reputation: 15492
One thing you are getting wrong here,it will be never be Configuration.company_name
, thats like access a Class property instead of a Object/Instance property,
It should be a instance of the Configuration Class. It would still be somewhat acceptable to use @KandagaBoggu's method in the other answer, but database access still almost everytime or from the Active Record’s query cache.But AR's query cache lives for the duration of a particular action (i.e. request ). You may want use something like Memcached for the objects to survive longer.
Upvotes: 0