我有三个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
为什么readonly?
在关联时调用first
时为真,而对limit
的关系无效?
我理解如果在查找记录时使用SQL片段会触发readonly
,但这不是这种情况。通过关联只是一个简单的has_many。唯一复杂的问题是它加入了STI模型。更重要的是,从最后两个示例中查看生成的SQL,它们是完全相同的!
我可以通过在关联上指定:readonly => false
来获得我想要的行为,但我想了解发生了什么。
Channel,MembershipChannel或ChannelMembership没有默认范围。以下是合作伙伴的关联声明:
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
答案 0 :(得分:2)
我能够通过一个基本的has_many:通过关联来重现你的问题,并且也是因为它导致了什么。
据我所知,只有在原始对象上调用reload方法时才会发生这种情况。我不确定这是因为任何重载正在做的事情,或者是因为某些属性标志正在重置?
我的第二个理论是它与
这个事实有关p.reload.channel_memberships.limit(1)
返回一个ActiveRecord :: Relation,通过它您可以获得第一个ChannelMembership和
p.reload.channel_memberships.first
直接从关联中加载它。也许某些重新加载重置某些缓存项目(我不知道AR源)的组合正在将该关联标记为只读。当您对其应用limit(1)范围时,它可能会以新的关系重置这些范围,并按照您的预期工作。
我会更多地了解ActiveRecord :: Persistence / Associations以获得完整答案。