Rails находит условия ... где атрибут не является столбцом базы данных - PullRequest
0 голосов
/ 26 августа 2010

Я думаю, можно с уверенностью сказать, что всем нравится делать что-то подобное в Rails:

Product.find(:all, :conditions => {:featured => true})

Это вернет все товары, для которых атрибут «Featured» (который является столбцом базы данных) имеет значение true. Но допустим, у меня есть метод для Product, подобный этому:

def display_ready?
     (self.photos.length > 0) && (File.exist?(self.file.path))
end

... и я хочу найти все продукты, где этот метод возвращает true. Я могу придумать несколько грязных способов сделать это, но я думаю, также можно с уверенностью сказать, что мы любим Rails, потому что большинство вещей не беспорядочные.

Я бы сказал, что это довольно распространенная проблема для меня ... Я должен был представить, что хороший ответ поможет многим людям. Какие-нибудь беспорядочные идеи?

Ответы [ 2 ]

5 голосов
/ 26 августа 2010

Единственный надежный способ отфильтровать их - это несколько уродливый метод извлечения всех записей и их запуска через выборку:

display_ready_products = Product.all.select(&:display_ready?)

Это крайне неэффективно, особенно если у вас есть большое количество продуктов, которые, вероятно, не подойдут.

Лучший способ сделать это - создать кеш счетчика для ваших фотографий, а также установить флаг при загрузке файла:

class Product < ActiveRecord::Base
  has_many :photos
end

class Photo < ActiveRecord::Base
  belongs_to :product, :counter_cache => true
end

Вам необходимо добавить столбец в таблицу Product:

add_column :products, :photos_count, :default => 0

Это даст вам столбец с количеством фотографий. Есть способ предварительно заполнить эти счетчики правильными числами в начале вместо нуля, но здесь нет необходимости вдаваться в это.

Добавить столбец для записи вашего файла флаг:

add_column :products, :file_exists, :boolean, :null => false, :default => false

Теперь активируйте это при сохранении:

class Product < ActiveRecord::Base
  before_save :assign_file_exists_flag

protected
  def assign_file_exists_flag
    self.file_exists = File.exist?(self.file.path)
  end
end

Поскольку эти два атрибута отображаются в столбцах базы данных, теперь вы можете напрямую запросить их:

Product.find(:all, :conditions => 'file_exists=1 AND photos_count>0')

Вы можете исправить это, написав две именованные области, которые будут инкапсулировать это поведение.

1 голос
/ 26 августа 2010

Вам нужно выбрать два уровня:

1) Выбрать все возможные строки из базы данных.Это происходит в БД.

2) В Ruby выберите допустимые строки из всех строк.Например,

possible_products = Product.find(:all, :conditions => {:featured => true})
products = possible_products.select{|p| p.display_ready?}

Добавлено:

Или:

products = Product.find(:all, :conditions => {:featured => true}).select {|p|
               p.display_ready?}

Второй выбор - это метод выбора объекта Array.Выбор очень удобный метод, наряду с обнаружением.(Detect исходит из Enumerable и смешивается с Array.)

...