简体   繁体   English

Ruby和Rails:元编程变量成为类方法

[英]Ruby and Rails: Metaprogramming variables to become class methods

I'm creating a model called Configuration and I have the following code and I want to make it more dynamic by using metaprogramming. 我正在创建一个名为Configuration的模型,我有以下代码,并且我想通过使用元编程使它更加动态。

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: 当前,访问company_name的唯一方法是在rails控制台中执行以下操作:

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. 我该如何做些更动态的事情,以便可以像这样访问值“ MyCompany”。

Configuration.company_name

> "MyCompany"

The reason to do this is to give allow fast customization of the application. 这样做的原因是允许快速定制应用程序。

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. 如果您有1000个配置变量,则可能必须考虑将缓存迁移到memcached等。

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

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, 您在这里弄错的一件事,永远不会是Configuration.company_name ,就像访问Class属性而不是Object / Instance属性,

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 (ie request ). 在另一个答案中使用@KandagaBoggu的方法仍然可以接受,但是几乎每次都可以访问数据库,也可以从Active Record的查询缓存中访问数据库。但是AR的查询缓存在特定操作(例如request)期间有效。 You may want use something like Memcached for the objects to survive longer. 您可能想要使用类似Memcached的对象来使对象生存更长的时间。

当服务器启动时,我们可以将这些常量值移到yml文件中,并将它们加载到变量中,并在需要时访问它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM