2012-06-25 1 views
3

Я использую Ruby on Rails 3.2.2, и я экспериментирую с камнем Squeel. Я хотел бы знать, если (каким-то образом, используя камень Squeel или нет), можно «добавить» предложения SQL, связанные с методом scope «непосредственно» в предложении where. То есть, у меня есть:Можно ли «добавить» предложения SQL, связанные с методом `scope`, в` where` method/clause?

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 ... 

I судимое sifters но те (по крайней мере для меня) предназначены для исключительно в других заявлениях Squeel. То есть, если я укажу фильтр, то я не могу использовать его для области ActiveRecord, потому что этот фильтр возвращает объект Squeel::Nodes::Predicate вместо ActiveRecord::Relation.

ответ

1

Вы должны опуститься в более сырой 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 

Или что-то вдоль этих линий.

0

Вы можете использовать цепи, такие как Article.by_author(user).by_editor(), но это объединяет все условия с AND. Таким образом, чтобы обойти эту проблему, вы можете написать отдельную области действия (не сцепление их) с помощью 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 

Или вы можете использовать просеиватели:

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 :: Отношение, так что вы можете теоретически еще больше их связать.