是否可以在`where`方法/子句中“添加”与`scope`方法相关的SQL子句?

时间:2012-06-25 17:50:47

标签: sql ruby-on-rails ruby ruby-on-rails-3 squeel

我正在使用Ruby on Rails 3.2.2,我正在试验Squeel gem。我想知道(在某种程度上,通过使用Squeel gem),可以在scope子句中“直接”“添加”与where方法相关的SQL子句。也就是说,我有:

class Article < ActiveRecord::Base
  # Note: This is a scope method.
  def self.created_by(user)
    where(:user_id => user.id)
  end

  # I would like to use a scope method like the following.
  #
  # Note: Code in the following method doesn't work, but it should help
  # understanding what I mean.
  def self.scope_method_name(user)
    where{ created_by(user) | ... & ... }
  end
end

因此,当我运行Article.scope_method_name(@current_user).to_sql时,它应返回如下内容:

SELECT articles.* FROM articles WHERE articles.user_id = 1 OR ... AND ...

我试过sifters但是那些(至少对我来说)打算在其他Squeel语句中使用 。也就是说,如果我声明了一个sifter,那么我就不能使用它来限定ActiveRecord的范围,因为该sifter会返回Squeel::Nodes::Predicate个对象而不是ActiveRecord::Relation

2 个答案:

答案 0 :(得分:1)

你必须为OR操作下拉到更原始的AREL

def self.scope_method_name(user)
  t = arel_table
  where(
    (t[:user_id].eq(user.id).or(
    t[:blah].eq('otherthing')
      ).and([:bleh].eq('thirdthing'))
    )
end

或类似的东西。

答案 1 :(得分:0)

您可以链接Article.by_author(user).by_editor()之类的范围,但这会加入ANDs的所有条件。因此,为了解决这个问题,您可以使用Squeel编写单独的范围(不链接它们),如:

class Article < ActiveRecord::Base

  scope :by_author, ->(user) { where{author_id == user.id} }
  scope :by_editor, ->(user) { where{editor_id == user.id} }
  scope :by_title, ->(token) { where{title =~ "%#{token}%"} }
  scope :by_author_or_editor, ->(user) { where{(author_id == user.id)|(editor_id == user.id)} }
  scope :by_author_or_editor_and_title, ->(user, token) { where{((author_id == user.id)|(editor_id == user.id))&(title =~ "%#{token}%")} }
end

或者你可以使用sifters:

class Article < ActiveRecord::Base

  sifter :sift_author do |user|
    author_id == user.id
  end

  sifter :sift_editor do |user|
    editor_id == user.id
  end

  sift :sift_title do |token|
    title =~ "%#{token}%"
  end

  scope :by_author, ->(user) { where{sift :sift_author, user} }
  scope :by_editor, ->(user) { where{sift :sift_editor, user} }
  scope :by_title, ->(token) { where{sift :sift_title, token} }
  scope :by_author_or_editor, -> (user) { where{(sift :sift_author, user)|(sift :sift_editor, user)} }
  scope :by_author_or_editor_and_title, ->(user, token) { where{((sift :sift_author, user)|(sift :sift_editor, user))&(sift :sift_title, token)} }
end

这为您提供了返回ActiveRecord :: Relation的范围,因此您可以在理论上进一步链接它们。