Используйте find для инициализации константы? - PullRequest
0 голосов
/ 30 июля 2009

Примерно так:

Категория класса

   SOME_CATEGORY = find_by_name("some category")

конец

Категория :: SOME_CATEGORY
попробовал без проблем, но хочу узнать, если это плохая идея, и причины, если таковые имеются.

спасибо

Ответы [ 3 ]

6 голосов
/ 01 августа 2009

Если вы не хотите обращаться к базе данных каждый раз, когда вам придется кэшировать модель. Есть несколько способов сделать это, но один быстрый способ - использовать 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
0 голосов
/ 30 июля 2009

Это не ужасная идея, но и не очень хорошая. Это не совсем соответствует тому, как Rails делает вещи. Во-первых, вы получите много уродливого постоянного кода. Слишком много ALL_CAPS_WORDS, и ваш Ruby начинает выглядеть как C ++. Bleah.

Для другого это негибко. Собираетесь ли вы сделать одну из этих констант для каждой категории? Если вы добавите новую категорию через два месяца, не забудете ли вы обновить код Rails, добавить новую константу, повторно развернуть ее и перезапустить сервер?

Если для вас важно иметь возможность легко получать доступ к категориям, а не повторять запросы к БД, вот немного метапрограммирования, которое автоматически их ищет и создает статические методы, подобные Лихтамбергу, для вас при первом доступе:

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 , кстати; если хотите узнать больше, посмотрите в книге «Кирка».

(Конечно, у вас все еще есть риск, что, поскольку все они запомнены, ваше приложение Rails не будет отражать любые изменения, которые вы вносите в объекты своей категории. Это предполагает, что изменения не произойдут или не произойдут Это действительно важно. Вам решать, является ли это предположение допустимым для вашего приложения. Вы всегда можете добавить в свой код обратный вызов after_update, который сбрасывает @@categories, если это проблема, но в этот момент это становится сложным .)

0 голосов
/ 30 июля 2009

Что вы хотите сделать?

Может быть:

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

Так что вы можете позвонить:

Category.some_category
=> <Category#2....>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...