Rails找到条件......其中attribute不是数据库列

tyb*_*103 0 methods activerecord attributes model ruby-on-rails

我认为每个人都喜欢在Rails中做这样的事情是安全的:

Product.find(:all, :conditions => {:featured => true})
Run Code Online (Sandbox Code Playgroud)

这将返回属性"features"(数据库列)为true的所有产品.但是,假设我在这样的产品上有一个方法:

def display_ready?
     (self.photos.length > 0) && (File.exist?(self.file.path))
end
Run Code Online (Sandbox Code Playgroud)

...我希望找到该方法返回true的所有产品.我可以想到几种混乱的方式,但我认为我们喜欢Rails也是安全的,因为大多数事情都不是很混乱.

我会说这对我来说是一个非常普遍的问题......我必须想象一个好的答案会帮助很多人.任何非杂乱的想法?

tad*_*man 5

过滤这些的唯一可靠方法是检索所有记录并通过选择运行它们的丑陋方法:

display_ready_products = Product.all.select(&:display_ready?)
Run Code Online (Sandbox Code Playgroud)

这种方法效率极低,特别是如果您有大量可能无法满足要求的产品.

更好的方法是为照片添加计数器缓存,并在上传文件时设置标记:

class Product < ActiveRecord::Base
  has_many :photos
end

class Photo < ActiveRecord::Base
  belongs_to :product, :counter_cache => true
end
Run Code Online (Sandbox Code Playgroud)

您需要在Product表中添加一列:

add_column :products, :photos_count, :default => 0
Run Code Online (Sandbox Code Playgroud)

这将为您提供包含照片数量的列.有一种方法可以在开始时使用正确的数字预先填充这些计数器而不是零,但是没有必要在这里进入.

添加一列以记录您的文件标志:

add_column :products, :file_exists, :boolean, :null => false, :default => false
Run Code Online (Sandbox Code Playgroud)

保存时触发此操作:

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
Run Code Online (Sandbox Code Playgroud)

由于这两个属性都呈现为数据库列,因此您现在可以直接查询它们:

Product.find(:all, :conditions => 'file_exists=1 AND photos_count>0')
Run Code Online (Sandbox Code Playgroud)

您可以通过编写两个封装该行为的命名范围来清理它.