2016-05-11 5 views
2

深い条件に基づいてデータベースを照会しようとしています。例として、私は、その主なペット特定の品種名を持つ人々のすべてを見つけるしたいと思います:深い条件でRailsでクエリを完了する方法は?

人>ペット>犬種>名前

モデルは次のようになります。

class Person 
    has_many pets 
    attr_accessor :primary_pet 
end 

class Pet 
    belongs_to Person 
    has_one Breed 
end 

class Breed 
    # no belonging relationship 
    attr_accessor :name 
end 

今、私は何ができる:

Person.find_each do |person| 
    puts person if primary_pet.breed.name == 'Norwich Terrier' 
end 

が、私はどこの方法でこれを行うための適切なクエリ構文を把握したいです。以下では動作しません:

Person.where(primary_pet.breed.name: 'Norwich Terrier').find_each do |person| 
    puts person 
end 
+3

これは、トリックを行います: 'Person.includes(ペット:犬種).where(品種:{名: 'ノーリッチ・テリア'})' – MrYoshiji

+0

HTTPSを: //thoughtbot.com/upcase/videos/advanced-querying-belongs-to –

答えて

1

私はマイナーな編集とモデルの関係を定式化し、これで終わった:

class Person < ActiveRecord::Base 
    has_many :pets 
    attr_accessor :primary_pet 
end 

class Pet < ActiveRecord::Base 
    belongs_to :person 
    belongs_to :breed 
end 

class Breed < ActiveRecord::Base 
    # no belonging relationship 
    attr_accessor :name 
end 

私は(それが実際に働いていた)を思い付いた最高のクエリは、このでした:

Person.joins(pets: :breed).where(breeds: { name: 'Norwich Terrier' }).where("people.primary_pet = pets.id") 

これはpetsためとbreedsに関係に参加することを言います。これにより、breeds構造体を使用して 'Norwich Terrier'をフィルタリングすることができます。それを終えて、pets.idに関連するprimary_pet_idでさらにフィルタリングします。

これは、あなたが質問で求めたものを得るはずです。ここで

は、私はそれをテスト方法は次のとおりです。

breed_names = ["Beagle", "Collie", "Norwich Terrier", "German Shepard", "Dachshund"] 
people_names = ["Barbara", "Connie", "Paula", "Gerald", "Dave"] 

# Add breeds 
breed_names.each {|name| Breed.create!(name: name) } 
# Add people 
people_names.each {|name| Person.create!(name: name) } 

# Add some pets 
people_names.each do |name| 
    person = Person.find_by(name: name) 
    breed_names.sample(3).each do |breed| 
    breed = Breed.find_by(name: breed_name) 
    Pet.create!(breed_id: breed.id, person_id: person.id) 
    end 
end 

# Assign the primary_pet for each person 
Person.all.each {|person| pet = person.pets.first ; person.update!(primary_pet: pet) if pet } 

# List all people and their pets by breed 
Person.all.each do |person| 
    puts "#{person.name}: #{person.pets.map {|pet| pet.breed.name}}" 
end 

# List all people and their primary pet breed 
Person.all.each do |person| 
    puts "#{person.name}: #{person.primary_pet ? person.primary_pet.breed.name : ''}" 
end 

# Run the query 
Person.joins(pets: :breed).where(breeds: { name: 'Norwich Terrier' }).where("people.primary_pet = pets.id") 
+0

'ActiveRecord :: ConfigurationError: 'breeds'という名前の関連がPerson'に見つかりませんでしたか?そして、私が知っている限りでは、結合の代わりに[メソッドを含む](http://apidock.com/rails/ActiveRecord/QueryMethods/includes)を使う方が良いと分かっています。 Imが間違っていれば私を訂正してください。 –

+1

@MartinZinovsky 'join 'メソッドと' includes'メソッドは、基本的に同じことをします(SQLの小さな違いが生成されます)が、まったく異なる目的のために存在します。 'join 'は、テーブルを明示的に結合し、他のクエリメソッド(例えば、' where)に対して追加のクエリ能力を提供するために使用されます。 'includes'は、熱心な読み込み関連を意図した暗黙的な結合に使用されます。望ましくない副作用があるかもしれないので、私はそれらを交換可能に使用しません。 'includes'は' join 'の代わりに動作することがよくありますが、必ずしもそうではありません。素晴らしい質問! :D –

+0

@DavidEnglishこれはあなたの質問に答えましたか?その場合は、回答の横にあるチェックマークをクリックして受け入れてください。チェックマークが緑色に変わります。アップホーテもいつでも歓迎です! –

関連する問題