使用find初始化常量?

时间:2009-07-30 16:04:32

标签: ruby-on-rails

这样的事情:

班级类别

   SOME_CATEGORY = find_by_name("some category")

类别:: SOME_CATEGORY
尝试没有问题,但想知道这是不是一个坏主意,以及原因,如果有的..

感谢

3 个答案:

答案 0 :(得分:6)

如果您不想在每次必须缓存模型时都访问数据库。有几种方法可以做到这一点,但一种快速方法是使用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

答案 1 :(得分:0)

你想做什么?

也许:

class Category
  def self.some_category
    Category.find_by_name("some category")
  end
end

所以你可以打电话:

Category.some_category
=> <Category#2....>

答案 2 :(得分:0)

这不是一个可怕的想法,但它也不是一个好主意。它并没有真正符合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回调,如果这是一个问题就会重置@@categories;但是在这一点上开始变得复杂。)