【问题标题】:How to scope has_many through association that uses custom key names?如何通过使用自定义键名的关联来确定 has_many 的范围?
【发布时间】:2017-07-27 21:23:55
【问题描述】:

试图学习如何通过我正在使用的关联正确导航 has_many,但我遇到了困难。我已经抽象了这里的类,以便它们更容易关联。

一本书有很多人物。 一个角色有很多书。 它与典型的 hmt 关联的不同之处在于,当一个角色与一本书关联时,它要么被添加为“好人”,要么被添加为“坏人”,例如:

book.bad_guys << character

我能够为 book.good_guys 提取结果就好了。让我陷入循环的是,每当我想反其道而行之,获取一个角色并找出他与哪些书相关联时,它会返回 Book::ActiveRecord_Associations_CollectionProxy 而不是实际的结果列表。

如果我执行 character.books.first 这就是输出(注意它是如何尝试查找“good_guy”属性而不是离开作为连接表一部分的 book 和 character 列)

Document Load (1.1ms)  SELECT  "books".* FROM "books" INNER JOIN "book_characters" ON "books"."id" = "book_characters"."good_guy" WHERE "book_characters"."character_id" = ? ORDER BY "books"."id" ASC LIMIT ?  [["character_id", 1], ["LIMIT", 1]]
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: book_characters.good_guy: SELECT  "books".* FROM "books" INNER JOIN "book_characters" ON "books"."id" = "book_characters"."good_guy" WHERE "book_characters"."character_id" = ? ORDER BY "books"."id" ASC LIMIT ?
from /home/linux/.rvm/gems/ruby-2.3.1/gems/sqlite3-1.3.11/lib/sqlite3/database.rb:91:in `initialize'    

我怀疑我需要确定 Character 模型如何执行它的搜索范围,即搜索 through 表并最终搜索到 Book 表,但我没有取得任何成功。

是否可以在字符模型上添加一个范围来修改它如何搜索直通表?或者我还需要做些什么来查找相关记录?提前感谢您提供的任何帮助!

class Character < ApplicationRecord
  has_many :book_characters
  has_many :books, -> { where(book_characters: ("character = :character.id")) }, :through => :book_characters # I don't think my wording is correct here

class Book < ApplicationRecord
  has_many :book_characters
  has_many :good_guys, through: :book_characters, :source => "character"
  has_many :bad_guys, through: :book_characters, :source => "character"

class BookCharacter < ApplicationRecord
  belongs_to :character
  belongs_to :book, :foreign_key => :bad_guy
  belongs_to :book, :foreign_key => :good_guy

这里是 BookCharacters 的迁移...

class CreateBookCharacters < ActiveRecord::Migration[5.0]
  def change 
    create_table :book_characters do |t|, 
      t.references :book, foreign_key: true
      t.references :entity

【问题讨论】:

  • 澄清一下,您希望能够进行类似character.books 的查询并让它返回显示该角色所在的所有书籍的关系?
  • @quicklikearabbit:是的,这就是我所追求的

标签: ruby-on-rails activerecord associations


【解决方案1】:

你的第一个问题是这样的:

class BookCharacter < ApplicationRecord
  belongs_to :character
  belongs_to :book, :foreign_key => :bad_guy
  belongs_to :book, :foreign_key => :good_guy

这里有两个问题。首先,您不能重复声明belongs_to :book。其次,当您说:foreign_key =&gt; :good_guy 时,rails 预计BookCharacter 将有一个名为good_guy 的字段。它没有。这就是你得到的原因:

no such column: book_characters.good_guy

所以,你需要更多类似的东西:

class BookCharacter < ApplicationRecord
  belongs_to :character
  belongs_to :book

那么,我相信您的作用域可能类似于:

class Character < ApplicationRecord
  has_many :book_characters
  has_many :books, -> { Book.where(book_characters: book_characters) }

我不能 100% 确定 book_characters: book_characters 位会像宣传的那样运行。因此,您可以尝试以下方法:

class Character < ApplicationRecord
  has_many :book_characters
  has_many :books, -> { Book.where(id: book_characters.pluck(:book_id)) }

说了这么多,我怀疑这个:

book.bad_guys << character

正在做你认为的事情。因为,您似乎没有在任何地方坚持“good_guy”或“bad_guy”的概念。所以,你可能并没有真正跟踪谁是好人,谁是坏人。

最后,我注意到您使用的是 SQLite。我不知道你最终会在哪里部署你的应用程序。但是,您可能需要考虑清楚。例如,Heroku 不使用 SQLite,要在 Heroku 上部署,您需要转换为 postgresql。吃点东西。

【讨论】:

  • 有趣...感谢您的详细回复,有很多值得咀嚼的东西!因此,如果我没看错,如果我想将 good_buys 与 bad_guys 分开,将它们添加为干预模型会更有意义吗?或者也许使用某种多态关联?最终的目标是能够让一本书的好人和坏人在他们之间产生一次相遇,但这种相遇将被这本书“拥有”,所以这就是促使分离的原因......(真正的目标是代表当事人之间的合法交易)
  • 有多种方法可以满足您的需求。我不希望您需要任何新模型 - 您可以在 BookCharacter 上跟踪好人/坏人。但是,你需要一个新的领域。而且,您需要更改将角色添加到书中的方式(同样,有多种方法可以实现)。试一试,如果您有具体问题,请告诉我们。
  • > “试一试,如果您有具体问题,请告诉我们。”谢谢你的帮助jvillian,会做的! :thumbs_up:
猜你喜欢
  • 2014-07-06
  • 2014-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-05
  • 1970-01-01
相关资源
最近更新 更多