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

发布于 2024-09-16 06:46:23 字数 474 浏览 4 评论 0原文

我认为可以肯定地说每个人都喜欢在 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,因为大多数事情并不混乱。

我想说这对我来说是一个很常见的问题......我必须想象一个好的答案会帮助很多人。有什么不乱七八糟的想法吗?

I think it's safe to say everyone loves doing something like this in Rails:

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

This will return all products where the attribute "featured" (which is a database column) is true. But let's say I have a method on Product like this:

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

...and I want to find all products where that method returns true. I can think of several messy ways of doing it, but I think it's also safe to say we love Rails because most things are not messy.

I'd say it's a pretty common problem for me... I'd have to imagine that a good answer will help many people. Any non-messy ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

身边 2024-09-23 06:46:23

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

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

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

The only reliable way to filter these is the somewhat ugly method of retrieving all records and running them through a select:

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

This is inefficient to the extreme especially if you have a large number of products which are probably not going to qualify.

The better way to do this is to have a counter cache for your photos, plus a flag set when your file is uploaded:

class Product < ActiveRecord::Base
  has_many :photos
end

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

You'll need to add a column to the Product table:

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

This will give you a column with the number of photos. There's a way to pre-populate these counters with the correct numbers at the start instead of zero, but there's no need to get into that here.

Add a column to record your file flag:

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

Now trigger this when saving:

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

Since these two attributes are rendered into database columns, you can now query on them directly:

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

You can clean that up by writing two named scopes that will encapsulate that behavior.

残花月 2024-09-23 06:46:23

您需要进行两级选择:

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

第二个select是Array对象的select方法。 select 和 detector 都是一个非常方便的方法。 (Detect 来自 Enumerable,与 Array 混合在一起。)

You need to do a two level select:

1) Select all possible rows from the database. This happens in the db.

2) Within Ruby, select the valid rows from all of the rows. Eg

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

Added:

Or:

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

The second select is the select method of the Array object. Select is a very handy method, along with detect. (Detect comes from Enumerable and is mixed in with Array.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文