【问题标题】:Two belong_to referring the same table + eager loading两个belong_to引用同一张表+急切加载
【发布时间】:2018-06-12 16:50:34
【问题描述】:

首先,基于这个(Rails association with multiple foreign keys)我想出了如何让两个belong_to指向同一张表。

我有类似的东西

class Book < ApplicationRecord
  belongs_to :author, inverse_of: :books
  belongs_to :co_author, inverse_of: :books, class_name: "Author"
end

class Author < ApplicationRecord
    has_many :books, ->(author) {
       unscope(:where).
       where("books.author_id = :author_id OR books.co_author_id = :author_id", author_id: author.id) 
    }
end

一切都好。我可以做任何一个

  • book.author
  • book.co_author
  • 作者.books

但是,有时我需要为多个作者急切加载书籍(以避免 N 次查询)。

我正在尝试做类似的事情:

Author.includes(books: :title).where(name: ["Lewis Carroll", "George Orwell"])

Rails 5 向我抛出:“ArgumentError: 关联范围 'books' 依赖于实例(范围块接受参数)。不支持预加载依赖于实例的范围。”

我想知道我应该怎么做?

我应该使用多对多关联吗?这听起来像是一个解决方案。但是,它看起来会引入它自己的问题(我需要“排序”,这意味着我需要明确区分主要作者和共同作者)。

只是想弄清楚我是否缺少一些更简单的解决方案......

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-5 eager-loading belongs-to


    【解决方案1】:

    试试这个:

     Author.where(name: ["Lewis Carroll", "George Orwell"]).include(:books).select(:title)
    

    【讨论】:

    • 它返回相同的错误:“ArgumentError: 关联范围 'books' 依赖于实例(范围块接受参数)。不支持预加载依赖于实例的范围。”
    【解决方案2】:

    为什么不使用HABTM 关系?例如:

    # Author model
    class Author < ApplicationRecord
      has_and_belongs_to_many :books, join_table: :books_authors
    end
    
    # Book model
    class Book < ApplicationRecord
      has_and_belongs_to_many :authors, join_table: :books_authors
    end
    
    # Create books_authors table
    class CreateBooksAuthorsTable < ActiveRecord::Migration
      def change
        create_table :books_authors do |t|
          t.references :book, index: true, foreign_key: true
          t.references :author, index: true, foreign_key: true
        end
      end
    end
    

    你可以像下面这样使用 eagerload:

    irb(main):007:0> Author.includes(:books).where(name: ["Lewis Carroll", "George Orwell"])
    
    Author Load (0.1ms)  SELECT  "authors".* FROM "authors" WHERE "authors"."name" IN (?, ?) LIMIT ?  [["name", "Lewis Correll"], ["name", "George Orwell"], ["LIMIT", 11]]
    HABTM_Books Load (0.1ms)  SELECT "books_authors".* FROM "books_authors" WHERE "books_authors"."author_id" IN (?, ?)  [["author_id", 1], ["author_id", 2]]
    Book Load (0.1ms)  SELECT "books".* FROM "books" WHERE "books"."id" IN (?, ?)  [["id", 1], ["id", 2]]
    

    【讨论】:

    • 首先,你说得对,多对多是一个更好的选择。我开始朝那个方向前进。但是我决定使用 has_many :through (vs HABTM),因为我需要“排序”(我需要知道谁是主要的“作者”,谁是“共同作者”。加入时需要额外的属性表,仅在 has_many :through 中支持。
    • 是的,没错,has_many :through 是这种情况下更好的选择。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-14
    • 2014-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多