【问题标题】:Add nested attribute to associated model in Rails将嵌套属性添加到 Rails 中的关联模型
【发布时间】:2017-04-25 17:39:54
【问题描述】:

我有三个使用 Active Record 关联的模型:

Book Model
has_many :checkouts

User Model
has_many :checkouts

Checkout Model
belongs_to :book
belongs_to :user

在我看来,我需要图书、结帐和结帐中的用户名。

通过使用Book.first.checkouts 我得到:

#<ActiveRecord::AssociationRelation
  [#<Checkout id: 30,
    checkout_date: "2017-04-13",
    return_date: nil,
    book_id: 118,
    user_id: 1,
    created_at: "2017-04-13 17:43:07",
    updated_at: "2017-04-13 17:43:07"
  >,#<Checkout id: 50,
    checkout_date: "2017-04-13",
    return_date: nil,
    book_id: 118,
    user_id: 1,
    created_at: "2017-04-14 00:33:34",
    updated_at: "2017-04-14 00:33:34">
  ]>

但是,我想要用户名,而不仅仅是 id。我试过Book.first.checkouts.map { |c| c.user.name },但只返回名称,我需要其余的结帐信息。理想情况下,我的数据(转换为 json)看起来像:

{
  name: "Book Name",
  checkouts:  [
    checkout_data: "Today",
    user_name: "Mary"
  ]
}

如何将用户名添加到我的结帐数据中?

【问题讨论】:

  • 您是否单独显示结帐,即.each 循环?你应该可以显示checkout.user.name
  • @Okomikeruko 是的,单独通过每个循环。 checkout.user.name 有效,但它只返回用户名。我需要结帐和用户名。我想知道是否可以将它添加到虚拟属性或类似的东西。
  • 我想我正在尝试合并 2 个对象的数据:checkoutsuser
  • 你是说你想让checkout.username做和checkout.user.name一样的事情吗?
  • 如果目标是优化您的 JSON 输出,该线程对此有一些答案:stackoverflow.com/questions/13678092/…

标签: ruby-on-rails ruby activerecord associations


【解决方案1】:

你可以在你的控制器上试试这个:

render json: @books, include: { checkout: { only: :checkout_date, include: { user: { only: :name } } }}

【讨论】:

  • 不知道这个!真的很不错
【解决方案2】:

您应该预先加载数据以防止 (N+1) 查询问题, 对于显示特定书籍的可能结帐:

book_id = <given book id>
book = Book.find(book_id)
checkouts = book.checkouts.includes(:user)
return_hash = {name: book.name, checkouts: []}
checkouts.each do |checkout|
    return_hash[:checkouts] << { checkout_data: checkout.checkout_date,
                                 user_name: checkout.user.name
                               }
end

【讨论】:

  • 这是我正在尝试的一种方法,但我想知道是否有更简单的方法。什么是 N+1 查询问题?
  • checkout.user 将为每次结帐向数据库触发 1 个查询,如果您使用包含 :user 则所有相应的用户将在单个 IN 查询中被预取
【解决方案3】:

为了包含其他解决方案,我发现这很有效:

checkouts = book.checkouts.unreturned.map do |checkout|
  checkout.attributes.merge({ user_name: checkout.user.name })
end

{ checkouts: checkouts, available: book.available?, book_id: book.id }

attributes.merge 成功了。

【讨论】:

  • 不要使用。 attributes.merge 在一个循环中,随着应用程序的增长,它将花费大量的执行时间,我在我的应用程序中遇到了同样的性能问题,使用 ruby​​-prof 来查看代码中的瓶颈
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多