2009-07-06 6 views
1

私は、コード内にたくさんの醜いSQLがなくても、Railsの魔法を使ってかなり複雑なクエリになると思っています。named_scope with has_many associations

私のデータベースはかなり専門的な生物医学的モデルを扱っているので、私は以下をより現実的なシナリオに翻訳します。

は、私はモデルのブックを持っている

にhas_many:章

と章その

belongs_toの:書籍

インスタンスの章は、name属性を持ち、名前は序文なることができると言うために、序文と章という付録がありますが、付録という章はありません。実際にこれらの任意の組み合わせ

私は序文と紹介と呼ばれる章の両方を持つすべての本を探しています。現時点では

I帳を呼び出す場合

Book 
    named_scope :has_chapter?, lambda { |chapter_names| 
    condition_string_array = [] 
    chapter_names.size.times{condition_string_array << "chapters.name = ?"} 
    condition_string = condition_string_array.join(" OR ") 
    {:joins => [:chapters] , :conditions => [condition_string, * chapter_names]} 
    } 

を次のように私はnamed_scopeを持っています。 has_chapter? ["preface"、 "introduction"]これは私に序文または紹介という章を持つすべての本を見つけます。どのように私はそれを分離して見つけることが似たようなことをすることができます両方章の序文と紹介?

私はSQLに精通していないので、どのような種類の結合が必要であり、名前付きスコープでこれを達成できるかどうかは不明です。

感謝

アンソニー

答えて

8

私は は序文と 導入という名前の両方の章を持っているすべての書籍を見つけるために探しています。

私は、postgresではなくmysqlを使用しますが、私はpostgresがサブクエリをサポートしていると思いますか?その後、

class Book 

    named_scope :has_preface, :conditions => "books.id IN (SELECT book_id FROM chapters WHERE chapters.name = 'preface')" 
    named_scope :has_introduction, :conditions => "books.id IN (SELECT book_id FROM chapters WHERE chapters.name = 'introduction')" 

end 

と:あなたのような何かを試みることができる

Book.has_preface.has_introduction 
+0

これは非常にうまくいきます。いくつかの指標を追加することが助けになりました。 – Anthony

+0

+1正確に私が探していたもの、ありがとう! – MiniQuark

+0

はい、PostgreSQLはサブクエリをサポートしています。これはMySQLよりも早くサポートされているので、それも同様に機能しています。 –

1

私は は序文と 導入をという名前の両方の章を持っているすべての書籍を見つけるために探しています。 あなたはnamed_scopeせずにこれを行うことができます

を次のように

は、現時点では私はnamed_scopeを持っています。

class Book < ActiveRecord::Base 
    has_many :chapters 

    def self.has_chapter?(chapter_names) 
    Chapter.find_all_by_name(chapter_names, :include => [:book]).map(&:book) 
    end 
end 
+0

これはうまく動作しているようです。私は他のスコープと一緒にチェーンすることができるので、私はnamed_scopeを好むだけの問題です。 私は引き続き調査しなければならない – Anthony

2

は私が

condition_string = Array.new(chapter_names.size, "chapters.name=?").join(" AND ") 

へのコードの集が好きで、これは確かに.Howeverに参加「OR」のために働き、これが意味するので動作しません参加しないという点でchapters.name結合の単一行は、例えば「前置詞」と「紹介」の両方でなければならない。DUPLEXこの

named_scope :has_chapters, lambda { |chapter_names| 
    {:joins => :chapters , :conditions => { :chapters => {:name => chapter_names}}, 
    :select => "books.*, COUNT(chapters.id) AS c_count", 
    :group => "books.id", :having => "c_count = #{chapter_names.is_a?(Array) ? chapter_names.size : 1}" } 
} 
を示唆したものの

アンでもすっきり私の元を行う方法「OR」参加は、私の元の問題を解決するためのRailsのフォーラム(Post link) 上の両面に

named_scope :has_chapter?, lambda { | chapter_names | 
    {:joins => [: chapters] , :conditions => { :chapters => {:name => chapter_names}}} 
} 

おかげで

これは、SQLのいくつかの風味では動作しますが、PostgreSQLでは動作しません。私は、コード

Book.column_names.collect{|column_name| "books.#{column_name}"}.join(",") 

named_scope : has_chapter?, lambda { | chapter_names | 
    {:joins => :chapters , :conditions => { :chapters => {:name => chapter_names}}, 
    :select => "books.* , COUNT(chapters.id)", 
    :group => Book.column_names.collect{|column_name| "books.#{column_name}"}.join(","), :having => "COUNT(chapters.id) = #{chapter_names.is_a?(Array) ? chapter_names.size : 1}" } 
} 

を使用する必要がありましたが*。あなたの本ですべての列を選択することはできませんので、PostgreSQLでは必要とし、その後の本BY GROUP。*各列がなければなりませんさ個別の名前:(

+0

より良い方法は::条件=> {:チャプター=> {:名前=> chapter_names}}ですが、私も好きです:conditions => ["chapters.chapter_names IN(?)" 、chapter_names] – MiniQuark