有没有更好的方法来使用范围编写此ActiveRecord Rails 4.2查询?

时间:2016-05-12 07:14:41

标签: ruby-on-rails activerecord

所以我建立了一个用户界面,让用户通过动物和/或教练为动物找到一个动物园,用于带有postgres的Rails 4应用程序。

有一系列动物复选框和一系列训练师复选框。用户可以检查培训师和动物部分中的多个复选框。

这是我用来构建查询的rails代码

animal_ids = [1, 2, 3]
trainer_ids = [1, 2] 

# OR query - either an animal or trainer can be present to find a zoo
a = Zoo.includes(:animals).where(animals: { id: animal_ids}) 
b = Zoo.includes(:trainers).where(trainers: { id: trainer_ids})
zoos = a+b

这导致控制台中出现4个sql查询。有没有更有效的方式来写这个?我应该使用具有OR条件的原始SQL吗?

模型设置

class Zoo < ActiveRecord::Base 
  has_many :animals, through: zoo_animals
  has_many :trainers, through: zoo_trainers
  has_many :zoo_trainers
  has_many :zoo_animals
end  

class Animal < ActiveRecord::Base
  has_many :zoos, through :zoo_animals
  has_many :zoo_animals
end  

class Trainer < ActiveRecord::Base
  has_many :zoos, through :zoo_trainers 
  has_many :zoo_trainers
end  

class ZooAnimal < ActiveRecord::Base
  belongs_to :animal
  belongs_to :zoo
end

class ZooTrainer < ActiveRecord::Base
  belongs_to :zoo
  belongs_to :trainer
end

2 个答案:

答案 0 :(得分:0)

是的,您可以自己指定where条款:

Zoo.includes(:animals, :trainers).references(:animals, :trainers).where("animals.id IN (?) OR trainers.id IN (?)", animal_ids, trainer_ids)

答案 1 :(得分:0)

您可以定义范围以查找zoo

class Zoo < ActiveRecord::Base
  scope :from_animal_and_trainer, -> (animal_ids, trainer_ids) {
    joins(:animals, :trainers).where(Animal.arel_table[:id].in(animal_ids)
                                      .or(Trainer.arel_table[:id].in(trainer_ids)))
  }
end

然后使用它:

animal_ids = [1, 2, 3]
trainer_ids = [1, 2]
zoos = Zoo.from_animal_and_trainer(animal_ids,  trainer_ids)

顺便说一下,这只会生成一个查询,因为我们在上面的查询中使用了joins