【问题标题】:Polymorphic associations and join syntax for defining scopes用于定义范围的多态关联和连接语法
【发布时间】:2020-05-14 11:15:48
【问题描述】:

我正在尝试定义一个引用我的多态关联上的属性“状态”的范围。

我的现实问题是我的文章和事件涉及特定项目。我将这些捕获为 item_references。我的文章和活动可以处于草稿或已发布状态。我希望能够提取发布关联(item_referenceable)状态的 item_references。

类似这样的:

scope :published_resource, -> { where("item_referenceable.published?") }

但这显然行不通,因为item_referenceable 是一个实例方法,而我在类级别工作。我怀疑我需要进入连接前端,但我正在努力寻找方法。

以下是我的代码的相关部分:

型号:

class Article < ApplicationRecord
  has_many :item_references, as: :item_referenceable
  accepts_nested_attributes_for :item_references, allow_destroy: true,
   :reject_if => proc { |att| att[:item_unique_id].blank? }
end

class Event < ApplicationRecord
  has_many :item_references, as: :item_referenceable
  accepts_nested_attributes_for :item_references, allow_destroy: true,
   :reject_if => proc { |att| att[:item_unique_id].blank? }
end

class ItemReference < ApplicationRecord
  belongs_to :item_referenceable, polymorphic: true

  scope :in_articles, -> { where("item_referenceable_type = 'Article'") }
end

架构提取:

create_table "events", id do |t|
t.string "title"
t.datetime "start_date_time"
t.datetime "end_date_time"
t.string "state"

create_table "article", id do |t|
t.string "title"
t.string "slug"
t.text "body"
t.string "state"

create_table "item_references", id do |t|
t.text "item_unique_reference"
t.string "item_referenceable_type"
t.bigint "item_referenceable_id"
t.index ["item_referenceable_type", "item_referenceable_id"], name: "idx_item_refs"

问题可能会扩大,因为我最终将涉及多个模型中的项目,例如课程、博客等。我想知道是否可以定义范围而不必指定特定的模型名称并使用 item_referenceable_type参考型号名称。

这是我失败的尝试:

scope :published_resource, -&gt; { joins(:item_referenceable_type).where('item_references.item_referenceable.published?') }

我最终会尝试生成一个 API,该 API 按 item_unique_id 显示引用该项目的所有文章和事件。

像这样:

{
 "title": "Retrieve all item references",
 "items": [
   {
     "item_unique_id": "O12",
     "articles": [
       {
         "resource_id": 1,
         "title": "Penguin",
         "state": "published",
         "slug": "test-article"
       }
      ],
     "events": []
   },

我已经使用ItemReference.all.group_by(&amp;:item_unique_id) 进入了上述阶段,但它会检索所有资源(事件/文章),无论它们是否已发布。

【问题讨论】:

  • 恐怕还是有点不清楚。首先 state 在哪里, state 是什么数据类型?是分别存储在ArticleEvent 中还是存储在ItemReference 中。其次,这里的最终目标是什么,能够致电ItemReferences.published_resources
  • 抱歉,不清楚。模型事件和文章上有一个属性状态。我可以打电话发表吗?如果 state == 'Published',则在所有返回 true 的实例上。是的,这正是我想要做的。我正在尝试准备一个 API 来显示所有引用特定项目的文章和事件,我只想显示已发布的文章和事件,所以 ItemReferences.published_resources
  • 好的。好吧,多态关联不一定允许您调用ItemReferences.published_resources 并取回EventArticle 对象,但每个项目都可以独立执行,例如scope :published { where(state: 'Published') } 如果放在Article 将允许您调用Article.published
  • 我已经可以调用 Article.published 或 Event.published 但问题是我的 API 需要按项目返回所有相关资源。我将编辑我的问题以尝试使其更清晰。感谢您提供帮助。
  • 是的,因为我提到多态关联不能这样做,因为连接的性质。如果您自己尝试,您将看到以下错误ActiveRecord::EagerLoadPolymorphicError: Cannot eagerly load the polymorphic association :item_referenceable。我建议为这个功能构建一个单独的类并独立查询每个类。这是我可以提供的例子。

标签: ruby-on-rails activerecord polymorphic-associations


【解决方案1】:

以下是我建议的处理方式:(简而言之,扩展功能几乎肯定是一项要求)

class Publishable 
   PUBLISHABLES = {articles: Article, events: Event}
   attr_reader :results
   attr_accessor :limit, :conditions   
   def initialize(conditions={})
      @conditions = conditions 
      @results = {} 
   end   

   def as_json(options={})
     fetch if results.empty?  
     results.as_json(options) 
   end  

   def published!
     conditions.merge!({stage: 'Published'})
     self 
   end 

   private 
     def fetch
       PUBLISHABLES.each do |node, klass| 
         results[node] = klass.where(conditions).limit(limit)
       end  
     end 
end 

那么你可以简单地调用

publishables = Publishable.new
publishables.published!
publishables.limit = 10 
publishables.results 

正如我所提到的,这只是为了给您一个示例而过于简化,我当然会考虑扩展此功能,但希望它可以帮助您指明方向

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-07
    • 1970-01-01
    • 2012-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多