使用find初始化常量?
像这样的东西:
类别
SOME_CATEGORY = find_by_name("some category")
结束
类别:: SOME_CATEGORY
尝试没有问题,但想知道这是一个坏主意,以及原因,如果有..
谢谢
如果您不想在每次必须缓存模型时都访问数据库。 有几种方法可以做到这一点,但一种快速方法是使用Memoization 。 这是在Rails 2.2中引入的。
class Category < ActiveRecord::Base class << self extend ActiveSupport::Memoizable def named(name) find_by_name(name) end memoize :named end end
像这样使用它。
Category.named("some category") # hits the database Category.named("some category") # doesn't hit the database
缓存应该跨请求保持持久性。 您可以通过传递true
作为最后一个参数来重置缓存。
Category.named("some category", true) # force hitting the database
你想让我做什么?
也许:
class Category def self.some_category Category.find_by_name("some category") end end
所以你可以打电话:
Category.some_category =>
这不是一个可怕的想法,但它也不是一个好主意。 它并没有真正符合Rails做事的方式。 首先,你会得到很多丑陋的常量代码。 太多的ALL_CAPS_WORDS和你的Ruby开始看起来像C ++。 Bleah。
另一方面,它不灵活。 你打算为每个类别制作这些常量之一吗? 如果您在两个月后添加新类别,您是否记得更新Rails代码,添加新常量,重新部署并重新启动服务器?
如果能够非常轻松地访问类别并且不重复数据库查询对您来说很重要,这里有一些元编程,它会自动查找它们并在第一次访问时为您创建像Lichtamberg这样的静态方法:
def self.method_missing(category, *args) # The 'self' makes this a class method @categories ||= {} if (@categories[category] = find_by_name(category.to_s)) class_eval "def self.#{category.to_s}; @categories[#{category}]; end" return @categories[category] end super end
有了这个方法,无论何时第一次调用Category.ham
,它都会创建一个返回find_by_name("ham")
值的类方法 – 这样在下次调用时查询和method_missing()
都不会再次运行它。 这几乎就是OpenStruct类的工作方式,BTW; 如果你想了解更多,请在Pickaxe书中查阅。
(当然你仍然有风险,因为这些都是记忆,你的Rails应用程序不会反映你对你的类别对象所做的任何改变。这假设改变不会发生或不重要您可以after_update
决定该假设是否对您的应用程序有效。您可以随时在代码中设置after_update
回调,如果这是一个问题,则会重置@@categories
;但此时开始变得复杂。)