【问题标题】:How to create a 'has_many through' association if a polymorphic association is involved?如果涉及多态关联,如何创建“has_many through”关联?
【发布时间】:2016-01-08 00:51:50
【问题描述】:

我有 4 个模型:模型 1 与模型 2 相关联,模型 2 与模型 3 相关联。模型 2 和 3 通过多态关联与模型 4 相关联。这一切都有效。我无法指定模型 1 和模型 4 之间的关联,因此它们以两种方式相关:

  1. 模型 1 - 模型 2 - 模型 4
  2. 模型 1 - 模型 2 - 模型 3 - 模型 4

您将在下面找到所有关联,除了模型 1 和模型 4 之间的关联:


作者模型:

has_many :books,     dependent: :destroy

图书模型:

belongs_to :author
has_many   :chapters, dependent: :destroy
has_many   :titles,   as: :titlesource,       # Polymorphic Association
                      dependent: :destroy

章节模型:

belongs_to :book
has_many   :titles,   as: :titlesource,       # Polymorphic Association
                      dependent: :destroy

标题模型:

belongs_to :titlesource, polymorphic: true

问题:假设您有上述关联,并且您想知道author 具有的titles,无论它们是书名还是章节名。我应该使用哪些关联来扩展上述设置? (我假设有has_many through

更新:如果我要寻找的只是书名,我希望将 has_many :titles, through: :books 添加到 Author 模型中会起作用。但事实并非如此。如果我添加该关联,则Author.first.titles 会产生错误undefined method 'titles'。我认为这与多态关联和命名有关......?我做错了什么?

章节标题就更难了。该关联通过Book 模型,然后通过Chapter 模型,然后到Title 模型。如何在作者模型中包含这些标题?我认为它必须是具有以下逻辑的代码(但显然这段代码是不正确的):

has_many :titles, through: :books && :books:chapters

更新:给出的两个答案使用 SQL。这些解决方案不会向数据库发送大量查询,如果经常使用该方法会导致问题吗?这些方法中的一种在性能上是否优于另一种?

【问题讨论】:

  • 不完全是book has many chapters chapters has many titles 现在从书中你可以包含Book.include({:chapters => :titles})的标题
  • 不确定这就是我要找的。我想要一个author 的所有titles 的列表。 title 要么与 bookchapter 有关系,但 chapterauthor 没有方向关系,因此通过 book
  • 所以这是第一作者的标题Author.first.books.map(&:titles)
  • @RajarshiDas 展开 =)
  • has_many :books, -> {includes :titles} 在作者上现在它将加载带有标题的书籍

标签: ruby-on-rails ruby associations


【解决方案1】:

如果您要在Author 上使用关联,例如has_many :titles, through: :books,只要您在Title 模型迁移上设置了titlesource_idtitlesource_type,它就应该正常工作。

但是,如果您要添加另一个以通过像 has_many :titles, through: :chapters 这样的章节获取标题,它将覆盖第一个,并且只会获取 titlesource_type = 'Chapter' 的标题。

因此,如果您不介意 sql,我建议您的解决方案是在 Author 模型中实现这样的方法。

  def titles
    Title.where(
      "(titles.titlesource_type = 'Book'
      AND titles.titlesource_id
      IN (SELECT books.id FROM books WHERE books.author_id = #{id}))
      OR (titles.titlesource_type = 'Chapter'
      AND titles.titlesource_id
      IN (SELECT chapters.id
      FROM books
      INNER JOIN chapters ON chapters.book_id = books.id
      WHERE books.author_id = #{id}))"
    )
  end

【讨论】:

  • 这不会产生很多数据库查询吗?
  • @Marty 在控制台中,您将看到一个查询,但该查询包含两个嵌套查询。
【解决方案2】:

如果您不需要 ActiveRecord 方法(如 whereorder),那么这将为您提供一系列标题。

def titles_array  # sacrificing ActiveRecord methods
  books.collect { |b| b.titles + b.chapters.collect { |c| c.titles } }
end

您仍然可以对单个数组元素使用 AR 方法,例如 titles_array.first.author

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-09-18
    • 2010-12-13
    • 1970-01-01
    • 1970-01-01
    • 2014-06-03
    • 1970-01-01
    • 2015-12-17
    • 2011-09-28
    相关资源
    最近更新 更多