【问题标题】:How do I write a Rails finder method through a chain of belongs_to associations?如何通过 belongs_to 关联链编写 Rails finder 方法?
【发布时间】:2020-01-14 22:00:36
【问题描述】:

我使用的是 Rails 5.1。当存在“belongs_to”关联链时,如何编写查找器方法?我有以下型号...

class Plan < ApplicationRecord
    ...
  has_many :plan_items, :dependent => :destroy


class PlanItem < ApplicationRecord
    ...
  belongs_to :offer, :optional => false


class Offer < ApplicationRecord
  belongs_to :package, :optional => false


class Package < ApplicationRecord
  has_and_belongs_to_many :items

我想编写一个查找器,它可以获取所有带有 id = "blah" 的项目的计划。但是以下失败了...

[19] pry(main)> Plan.joins(plan_items: :offer).joins(packages: :item).where(:item => {:id => "abac"}).count
ActiveRecord::ConfigurationError: Can't join 'Plan' to association named 'packages'; perhaps you misspelled it?
from /Users/davea/.rvm/gems/ruby-2.5.1/gems/activerecord-5.2.2.1/lib/active_record/associations/join_dependency.rb:188:in `find_reflection'

当有一个 belongs_to 关联链时,我如何编写查找器?

【问题讨论】:

  • 您的迁移情况如何?
  • 嘿@SebastianPalma!很高兴在线程上见到你。我会尝试挖掘这些。请原谅我的问题,但为什么迁移很重要?是否可以根据给定的信息构建查找器?
  • 这样,(至少对我而言)创建一个示例应用程序来测试和详细说明此案例的答案会更容易。
  • 好吧,让我看看我能在这里做什么。

标签: ruby-on-rails ruby-on-rails-5 associations belongs-to finder


【解决方案1】:

首先,您的表名可能是错误的。二、belong_to关联之间传递方法,可以使用delegate

【讨论】:

    【解决方案2】:

    我假设PlanItemPlanItem 之间的连接表(这将符合Rails 命名约定)。这可以通过through 关联和范围巧妙地完成。我会这样做...

    class Plan < ApplicationRecord
      has_many :plan_items, dependent: :destroy
      has_many :items, through: :plan_items
    
      scope :blah_items { items.id_of_blah }
    
    class PlanItem < ApplicationRecord
      belongs_to :offer, optional: false
      belongs_to :item
    
    class Item < ApplicationRecord
      scope :id_of_blah { where(id: 'blah') }
    

    然后您可以这样称呼它...Plan.with_blah_items,或者如果您有计划的活动记录集合,您可以使用范围缩小它plans.with_blah_items

    由于 ActiveRecord 关联将返回 ActiveRecord 关系,您可以将它们与任何其他活动记录方法链接起来(例如Plan.first.items.where(item: { id: 'blah' }) Scopes 只是让它变得漂亮和整洁。:)

    如果PlanItem 不是 Plan 和 Item 之间的连接表,您应该做的第一件事就是重命名它。这不仅仅是一个最佳实践,rails 会花费大量时间来假设事物的名称,这可能会导致错误。重命名后,您应该在 Plan 和 Item 之间创建一个名为 PlanItem 的连接表。如果这些表之间的连接对您的应用程序架构没有意义,您总是可以将through 关联串在一起,但这会产生代码异味。

    如果您不想弄乱范围,您可以随时进行类似plan.items.where(items: { id: 'blah' }) 的查询。

    希望有帮助!

    【讨论】:

    • PlanItem 不是一个连接表——它有一个列“offer_id”。有没有办法编写查找器查询而不添加您在上面指定的额外“通过”关联?
    • 你可以在Plan 上有一个类方法,它只运行一个查询并返回你想要的计划。这基本上就是您上面的查询,但我认为您错过了关联的时态。正如错误告诉您的那样,您在定义关联时放置了“packages”而不是“package”。 Plan.joins(plan_items: { offer: { package: :items } }).where(items: { id: 'blah }) 应该可以满足您的需求,但绝对不是理想的解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多