【问题标题】:Rails scope by absence of has_one polymorphic association由于缺少 has_one 多态关联,Rails 范围
【发布时间】:2015-12-07 10:00:47
【问题描述】:

我的记录没有被删除,而是通过在多态 record_invalidations 表中创建条目而无效。

设置如下:

class RecordInvalidation < ActiveRecord::Base
  belongs_to :archivable, polymorphic: true
end


class Record < ActiveRecord::Base
  has_one :invalidation, class_name: "RecordInvalidation", as: :archivable

  def self.default_scope
    where(invalidation: nil)
  end
end

(有多个记录类,因此是多态关系。)

问题:我如何创建一个范围,它根据另一个类中指向相关类的条目不存在返回记录。

当前代码不起作用,因为关系指针在 records_invalidations 表中,而不是 records 表中。

更新 2

record_invalidation 类与表名匹配得很好,我认为问题是列名。这是(简化的)架构:

create_table "records", force: :cascade do |t|
  t.text     "content",        null: false
end

create_table "record_invalidations", force: :cascade do |t|
  t.integer  "archivable_id"
  t.string   "archivable_type"
end

更新 3

我知道为什么会发生第一个错误,所以我删除了该更新。 现在我传递了我在 SQL 查询中加入的正确表名,但我有许多参数不匹配。我可以将另一个参数传递给 where 子句吗?

self.joins(:invalidation).where('record_invalidations.id is null')

给予:

ActiveRecord::StatementInvalid: PG::ProtocolViolation: ERROR:  bind 
message supplies 1 parameters, but prepared statement "a56" requires 2

: SELECT  "records".* FROM "records" 
    INNER JOIN "record_invalidations" ON 
    "record_invalidations"."archivable_id" = "records"."id" AND 
    "record_invalidations"."archivable_type" = $1 WHERE 
    (record_invalidations.id is null) AND "plans"."id" = $2 LIMIT 1

【问题讨论】:

  • 我现在无法检查这个因此评论,但我认为你可以做.joins(:invalidation).where('invalidations.id is null')或类似的,让我知道它是否有效。
  • 更近了!我试过: self.joins(:invalidation).where('invalidations.id is null') 并得到了一个非常接近的 SQL 输出,但看到一个错误: ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR: missing FROM-clause entry对于表“无效”第 1 行:...cord_invalidations"."archivable_type" = $1 WHERE (invalidati... ^
  • 您可以在 RecordInvalidation 类中尝试self.table_name = 'records'(或任何实际的表名)吗?也许旧的范围会起作用 - 在这种情况下?
  • 好的,现在更有意义了 :) self.joins(:invalidation).where('records.id is null') 怎么样,我的错。
  • 最后一个错误已修复(耶!),但新的挑战者接近(嘘!)。

标签: ruby-on-rails polymorphic-associations default-scope


【解决方案1】:

这可能不是最有效的方法,但确实有效:

def self.default_scope
  # Only show records that were not invalidated
  # Makes a list of all invalidated record ids in a subquery then checks for id
  where.not(:id => RecordInvalidation.select(:archivable_id)
                                     .where(archivable_type: self.name)
                                     .uniq)
end

感谢rails scope to check if association does NOT exist

我刚刚为该答案添加了多态关联所需的过滤。

如果有人有更好的解决方案,请随时添加,我会接受而不是我自己的。

【讨论】:

    猜你喜欢
    • 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
    相关资源
    最近更新 更多