Rails:为has_many和has_many:通过关联一次获取记录

时间:2011-02-21 08:44:22

标签: ruby-on-rails refactoring associations

鉴于以下模型:

用户

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

贷款

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关系定义查询,但这似乎也不正确。

2 个答案:

答案 0 :(得分:1)

以下是我最终要做的事情。

使用meta_where gem可以使用以下方法来改善这种情况:

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

此方法返回关系对象并仅生成一个SQL查询。是否应该找到这种方法的意见?现在我正在User课程中学习。

答案 1 :(得分:0)

在模型中使用它:

def as_json(options={})
super(include: { trades: { include:  :trades } })
end