代码之家  ›  专栏  ›  技术社区  ›  tybro0103

Rails查找条件…其中属性不是数据库列

  •  0
  • tybro0103  · 技术社区  · 14 年前

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

    这将返回属性“featured”(数据库列)为true的所有产品。但假设我对产品有这样一种方法:

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

    …我想找到所有该方法返回true的产品。我可以想出几种乱七八糟的方法,但我认为可以肯定地说,我们喜欢Rails,因为大多数事情并不乱七八糟。

    对我来说这是个很常见的问题。。。我不得不想象一个好的答案会帮助很多人。有什么好主意吗?

    2 回复  |  直到 14 年前
        1
  •  5
  •   tadman    14 年前

    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
    

    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')
    

    您可以通过编写两个将封装该行为的命名作用域来清除这个问题。

        2
  •  1
  •   Larry K    14 年前

    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?}
    

    第二个选择是数组对象的选择方法。选择是一个非常方便的方法,连同检测。(Detect来自Enumerable,并与数组混合在一起。)