Tôi đã tìm thấy rất ít về cách người ta có thể viết phạm vi cho các mối liên hệ đa hình trong đường ray, hãy để một mình cách viết truy vấn trên các liên kết đa hình.Phạm vi và truy vấn với các hiệp hội đa hình
Trong tài liệu Rails, tôi đã xem Polymorphic Associations section, Joining Tables section và Scopes section. Tôi cũng đã thực hiện phần googling công bằng của mình.
Hãy thiết lập này ví dụ:
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
Vì vậy, một Pet
có thể được animal_type
"Chó", "Cát", hay "Bird".
Để hiển thị tất cả các cấu trúc bảng: ở đây là tôi 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
sau đó tôi đã đi trước và thực hiện một số hồ sơ:
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
Và sau đó tôi đã đi và thực hiện một số pet
hồ sơ:
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")
Và điều đó là thiết lập! Bây giờ phần khó khăn: Tôi muốn tạo ra một số phạm vi trên mô hình Pet
mà đào sâu vào các hiệp hội đa hình.
Dưới đây là một số phạm vi tôi muốn viết:
- Hãy cho tôi tất cả các
Pets
của animal_type == "Dog" có thể ngồi - Hãy cho tôi tất cả các
Pets
của animal_type == "Cát" đã giết chết ít nhất 10 con chuột - Cho tôi tất cả
Pets
KHÔNG phải là cả hai "animal" và không thể ngồi được. (Nói cách khác: Hãy cho tôi tất cả các vật nuôi: tất cả trong số họ: trừ cho chó mà không thể ngồi)
Vì vậy, trong mô hình Pet
tôi, tôi sẽ muốn đặt phạm vi của tôi trong đó:
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
Tôi thấy nó khá khó khăn để viết những phạm vi này.
Một số nội dung tôi tìm thấy trực tuyến làm cho nó trông giống như bạn chỉ có thể viết các phạm vi này với SQL thô. Tôi tự hỏi nếu có thể sử dụng cú pháp Hash cho các phạm vi này thay thế.
Mọi mẹo/trợ giúp sẽ được đánh giá cao!
'self.remove_dogs_that_cannot_sit' có thể được thực hiện nhanh hơn bằng cách sử dụng một bao gồm trên' động vật'. Hãy thử 'all.includes (: animal) .reject {| pet | pet.animal_type == "Dog" &&! pet.animal.sits} ' – chrismanderson
lưu ý tinh tế của nó nhưng khi bạn nhấn phần" .reject "bạn đang thực sự rơi vào ruby và để lại SQL đằng sau, do đó tại sao nó chậm. Bạn có thể chuỗi các phạm vi AREL và ở lại trong SQL, ví dụ:by_dogs.where (ngồi: false) nên tương đương, giả sử bạn có NOT NULL và mặc định là false set trên cột boolean trong db. IIRC, tôi có thể sai khi tôi rời khỏi đỉnh đầu của tôi, nhưng ".all" được ngụ ý và không cần thiết khi bạn đang có chuỗi AREL miễn là bạn có một phạm vi hiện diện. – engineerDave