Why is my has_many read-only through the linked record (sometimes)?

I have three ActiveRecord models: Partner, MembershipChannel (which is the STI model inheriting from the channel) and ChannelMembership (I was not responsible for naming these models ...)

When I load ChannelMembership through an affiliate association, I sometimes (!) End up reading only. This is in Rails 3.0.9. The same code did not behave like this in 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

Why is readonly?true when called firstin an association, but not in relation to limit?

I understand what readonlystarts if I use SQL fragments when searching for a record, but this is not the case here. This is just a simple association. The only complicating circumstance is that it joins the STI model. What else, looking at the generated SQL from the last two examples, they are identical!

I can get the behavior that I want by specifying :readonly => falsein the association, but I want to understand what is happening.

There are no default scopes in Channel, MembershipChannel, or ChannelMembership. Here is the association announcement for the Partner:

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

Here is the generated SQL from my logs:

  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
+5
source share
1 answer

has_many: , , .

, , . , - -, , , , , reset?

, - ,

p.reload.channel_memberships.limit(1)

ActiveRecord:: Relation, ChannelMembership,

p.reload.channel_memberships.first

. , ( AR) . (1) , , .

ActiveRecord:: Persistence/Associations .

+2

All Articles