Rails: извлекает записи сразу для has_many и has_many: через ассоциации - PullRequest
0 голосов
/ 21 февраля 2011

Учитывая следующие модели:

Пользователь

class User < ActiveRecord::Base
  has_many :given_loans,    :class_name => "Loan", :foreign_key => "lender_id"
  has_many :received_loans, :class_name => "Loan", :foreign_key => "borrower_id"
  has_many :borrowed_books, :class_name => "Book", :foreign_key => "borrower_id", :through => :received_loans
  has_many :own_books,      :class_name => "Book", :foreign_key => "owner_id"
end

Книга

class Book < ActiveRecord::Base
  belongs_to :owner,     :class_name => "User", :foreign_key => "owner_id"
  has_many   :loans,     :foreign_key => "borrowed_book_id"
  has_many   :borrowers, :through => "loans",   :foreign_key => "borrowed_book_id"
end

Loan

class Loan < ActiveRecord::Base
  belongs_to :borrowed_book, :class_name => "Book", :foreign_key => "borrowed_book_id"
  belongs_to :borrower,      :class_name => "User", :foreign_key => "borrower_id"
  belongs_to :lender,        :class_name => "User", :foreign_key => "lender_id"
end

Эти отношения, кажется, работают нормально.

Теперь я хотел бы запросить все книги для пользователя, включая заимствованные и принадлежащие ему книги, которые я сейчас делаю так:

def books
  own_books + borrowed_books
end

Этот метод, естественно, вызывает два SQL-запроса:

Book Load (0.4ms)  SELECT "books".* FROM "books" WHERE ("books".owner_id = 1)
Book Load (0.3ms)  SELECT "books".* FROM "books" INNER JOIN "loans" ON "books".id = "loans".borrowed_book_id WHERE (("loans".borrower_id = 1))

Кроме того, я не могу запускать методы активной записи, такие как limit или ордер против этого выбора, что было бы неплохо иметь. В конце концов, я беру книги с одного стола.

Я предполагаю, что есть лучший (более "Rails") и более эффективный способ сделать это. Кто-нибудь хочет указать мне правильное направление ? Ура!


P.S .: Одним из возможных решений, которое пришло на ум, было определение запроса для отношения has_many :books, но это тоже не совсем правильно.

1 Ответ

1 голос
/ 24 февраля 2011

Вот что я в итоге сделал.

Используя гем meta_where , можно улучшить ситуацию следующим методом:

def books
  Book.includes(:loans).where({ "owner_id" => self.id } | { "loans.borrower_id" => self.id })
end

Этот метод возвращает объект отношения и создает только один SQL-запрос. Любые мнения, где этот метод должен быть расположен? Прямо сейчас у меня это в классе User.

...