我很少发现如何在rails中为多态关联编写范围,更不用说如何编写关于多态关联的查询。具有多态关联的范围和查询
在Rails文档中,我查看了Polymorphic Associations section,Joining Tables section和Scopes section。我也做了我的公平份额谷歌搜索。
采取这种设置,例如:
class Pet < ActiveRecord::Base
belongs_to :animal, polymorphic: true
end
class Dog < ActiveRecord::Base
has_many :pets, as: :animal
end
class Cat < ActiveRecord::Base
has_many :pets, as: :animal
end
class Bird < ActiveRecord::Base
has_many :pets, as: :animal
end
所以一个Pet
可以是animal_type
“狗”, “猫”,或 “鸟”。
来显示所有的表结构:这里是我的schema.rb:
create_table "birds", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "cats", force: :cascade do |t|
t.integer "killed_mice"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "dogs", force: :cascade do |t|
t.boolean "sits"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "pets", force: :cascade do |t|
t.string "name"
t.integer "animal_id"
t.string "animal_type"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
然后我继续做了一些记录:
Dog.create(sits: false)
Dog.create(sits: true)
Dog.create(sits: true) #Dog record that will not be tied to a pet
Cat.create(killed_mice: 2)
Cat.create(killed_mice: 15)
Cat.create(killed_mice: 15) #Cat record that will not be tied to a pet
Bird.create
然后我去了,做了一些pet
记录:
Pet.create(name: 'dog1', animal_id: 1, animal_type: "Dog")
Pet.create(name: 'dog2', animal_id: 2, animal_type: "Dog")
Pet.create(name: 'cat1', animal_id: 1, animal_type: "Cat")
Pet.create(name: 'cat2', animal_id: 2, animal_type: "Cat")
Pet.create(name: 'bird1', animal_id: 1, animal_type: "Bird")
而且,是设置!现在最难的部分是:我想在Pet
模型上创建一些范围,以挖掘多态关联。
这里有一些领域,我想这样写:
- 给我你所有animal_type ==“狗”,可以坐
- 给我animal_type的所有
Pets
的Pets
==“猫”已杀死至少10只老鼠 - 给我所有的
Pets
不是既animal_type“狗”,也不能坐。 (换句话说:给我所有的宠物:所有的人:除了狗,不能坐)
所以在我Pet
模式,我希望把我的范围在那里:
class Pet < ActiveRecord::Base
belongs_to :animal, polymorphic: true
scope :sitting_dogs, -> {#query goes here}
scope :killer_cats, -> {#query goes here}
scope :remove_dogs_that_cannot_sit, -> {#query goes here} #only removes pet records of dogs that cannot sit. All other pet records are returned
end
我发现编写这些示波器非常困难。
我在网上找到的一些东西使它看起来像只能用原始SQL写这些范围。我想知道是否可以使用这些范围的哈希语法来代替。
任何提示/帮助将不胜感激!
'self.remove_dogs_that_cannot_sit'可以通过在'animal'上使用include来加快速度。尝试'all.includes(:animal).reject {| pet | pet.animal_type ==“Dog”&&!pet.animal.sits}' – chrismanderson
请注意它的细微之处,但是当您点击“.reject”部分时,您实际上正在抛弃ruby并将SQL留在后面,因此它的速度很慢。您可以链接AREL范围并保留在SQL中,例如by_dogs.where(sits:false)应该是等效的,假设你在数据库中的布尔列上有NOT NULL和默认假设置。 IIRC,我可能是错的,因为我要离开我的头顶,但只要你有一个范围存在,当你连接AREL范围时,“.all”就是暗示和不必要的。 – engineerDave