【问题标题】:Why is my has_many through associated record (sometimes) readonly?为什么我的 has_many 通过关联记录(有时)是只读的?
【发布时间】:2011-10-30 11:48:11
【问题描述】:

我有三个 ActiveRecord 模型:Partner、MembershipChannel(这是一个 STI 模型,继承自 Channel)和 ChannelMembership(我不负责命名这些模型……)

当我通过合作伙伴关联加载 ChannelMembership 时,有时(!)会得到一个只读记录。这是在 Rails 3.0.9 中。相同的代码在 2.3.11 中没有这种行为。

> p = Partner.first
> p.channel_memberships.map(&:readonly?)
# => [false, false, false, false, false, false]
> p.reload.channel_memberships.limit(1).first.readonly?
# => false
> p.reload.channel_memberships.first.readonly?
# => true

为什么在关联上调用firstreadonly? 为真,而不是在来自limit 的关系上调用?

我知道如果我在查找记录时使用 SQL 片段会触发readonly,但这里不是这种情况。它只是一个简单的 has_many 通过关联。唯一复杂的是它加入了 STI 模型。更何况,看看最后两个例子生成的SQL,它们是一样的!

我可以通过在关联上指定:readonly => false 来获得我想要的行为,但我想了解发生了什么。

Channel、MembershipChannel 或 ChannelMembership 上没有默认范围。以下是关于 Partner 的关联声明:

class Partner
  has_many :membership_channels
  has_many :channel_memberships, :through => :membership_channels
end

这是从我的日志中生成的 SQL:

  Partner Load (0.4ms)  SELECT "partners".* FROM "partners" LIMIT 1
  ChannelMembership Load (0.7ms)  SELECT "channel_memberships".* FROM "channel_memberships" INNER JOIN "channels" ON "channel_memberships".channel_id = "channels".id WHERE (("channels".partner_id = 2) AND (("channels"."type" = 'MembershipChannel')))
  Partner Load (0.5ms)  SELECT "partners".* FROM "partners" WHERE "partners"."id" = 2 LIMIT 1
  ChannelMembership Load (1.0ms)  SELECT "channel_memberships".* FROM "channel_memberships" INNER JOIN "channels" ON "channel_memberships".channel_id = "channels".id WHERE (("channels".partner_id = 2) AND (("channels"."type" = 'MembershipChannel'))) LIMIT 1
  Partner Load (0.4ms)  SELECT "partners".* FROM "partners" WHERE "partners"."id" = 2 LIMIT 1
  ChannelMembership Load (0.6ms)  SELECT "channel_memberships".* FROM "channel_memberships" INNER JOIN "channels" ON "channel_memberships".channel_id = "channels".id WHERE (("channels".partner_id = 2) AND (("channels"."type" = 'MembershipChannel'))) LIMIT 1

【问题讨论】:

    标签: ruby ruby-on-rails-3 activerecord has-many-through


    【解决方案1】:

    我能够通过基本的 has_many :通过关联重现您的问题,并且还知道是什么原因造成的。

    据我所知,只有在对原始对象调用 reload 方法时才会发生这种情况。我不确定这是因为 reload 做了什么特别的事情,还是因为某些属性标志正在被重置?

    我的第二个理论是,它与以下事实有关

    p.reload.channel_memberships.limit(1)
    

    返回一个 ActiveRecord::Relation,您可以通过它获得您的第一个 ChannelMembership,并且

    p.reload.channel_memberships.first
    

    直接从关联加载它。也许重新加载重置某些缓存项目的某种组合(我不知道 AR 源)将关联标记为只读。当您对其应用 limit(1) 范围时,它可能会在新关系中重置它们,并按您的预期工作。

    为了完整的答案,我会多讨论一下 ActiveRecord::Persistence / Associations。

    【讨论】:

    • 是的,我认为这将是我深入研究 AR 和 AREL 的好时机。无论如何,我一直想学习如何绕过 rails 源。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-14
    • 2012-07-29
    • 1970-01-01
    • 1970-01-01
    • 2011-12-27
    • 1970-01-01
    相关资源
    最近更新 更多