复杂的选择集,Rails方式?

Kev*_*ker 1 ruby activerecord select ruby-on-rails

假设你有一个"作者"对象,它有几本书,你想要在模型中构建一些方法.您的基本设置如下所示:

class Author
  def book_count(fiction = nil, genre = nil, published = nil)
  end
end
Run Code Online (Sandbox Code Playgroud)

对于每个参数,您有几种方法可以操作:

fiction = true #retrieve all fiction books
fiction = false #retrieve all nonfiction
fiction = nil #retrieve books, not accounting for type

genre = nil #retrieve books, not accounting for genre
genre = some_num #retrieve books with a specific genre id

published = true #retrieve all published
published = false #retrieve all unpublished
published = nil #retrieve books, not accounting for published
Run Code Online (Sandbox Code Playgroud)

现在,我为其中的一些写了一个基本的select语句,类似于:

if published == true
  return self.books.select{ |b| b.published == true }.size
elsif published == false
  return self.books.select{ |b| b.published == false}.size
else
  return self.books.size
end
Run Code Online (Sandbox Code Playgroud)

当我只有一两个论点时,这很笨拙,但很容易.但是,随着客户端请求向该方法添加更多条件,编写越来越繁琐.

处理这个问题最好的"轨道"方式是什么?

谢谢!

Oli*_*ves 6

范围,(或"named_scopes",如果你使用Rails <3)可能是最好的方法.

以下是针对rails 3,但可以通过较小的语法调整来完成您可以在模型中创建一组范围.即

scope :with_genre, lambda {|genre| where(:genre => genre) unless genre.nil?}
scope :published, lambda{|published| where(:published => published) unless published.nil?}
scope :fiction,, lambda{|fiction| where(:fiction => fiction) unless fiction.nil?}
Run Code Online (Sandbox Code Playgroud)

等等

然后,无论何时需要访问它们,您都可以执行以下操作

def book_count(..)
  self.books.with_genre(genre).published(published).fiction(fiction).size
end
Run Code Online (Sandbox Code Playgroud)

此外,您可以将book_count参数设置为哈希值,然后您可以拥有任意数量的选项,而无需使该函数具有大量参数.