2011-08-19 6 views
5

Mam trzy modele ActiveRecord: Partnerzy, MembershipChannel (który jest modelem STI, dziedziczenie z Kanału) i ChannelMembership (I nie był odpowiedzialny za nazywanie tych modeli ...)Dlaczego moje has_many przez skojarzony rekord (czasami) tylko do odczytu?

Kiedy załadować ChannelMembership przez stowarzyszenia Partner, ja czasem (!) kończy się na zapisie tylko do odczytu. To jest w Railsach 3.0.9. Ten sam kod nie zachowywał się w ten sposób w 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 

Dlaczego readonly? prawdziwe, gdy first nazywa sprawie stowarzyszenia, ale nie w związku z limit?

Rozumiem, że readonly jest wyzwalane, jeśli używam fragmentów SQL podczas znajdowania rekordu, ale tak nie jest w tym przypadku. Jest to tylko zwykła kombinacja. Jedyną komplikacją jest to, że dołącza się do modelu STI. Co więcej, patrząc na wygenerowany SQL z dwóch ostatnich przykładów, są one identyczne!

Mogę uzyskać pożądane zachowanie, określając :readonly => false na skojarzenie, ale chcę zrozumieć, co się dzieje.

Brak domyślnych zakresów w kanale, MembershipChannel lub ChannelMembership. Oto deklaracja stowarzyszenie na Partner:

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

Oto generowane SQL z moich logów:

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 

Odpowiedz

2

byłem w stanie odtworzyć problemu poprzez podstawowy has_many: poprzez stowarzyszenia i jestem również do co to powoduje.

Z tego co wiem, dzieje się tak tylko wtedy, gdy metoda ponownego ładowania jest wywoływana na oryginalnym obiekcie. Nie jestem pewien, czy dzieje się tak z powodu czegoś, co przeładowuje konkretnie, czy może dlatego, że niektóre flagi atrybutów są resetowane?

Moja druga teoria jest taka, że ​​to ma coś wspólnego z faktem, że

p.reload.channel_memberships.limit(1) 

zwracającej ActiveRecord :: Relacja dzięki której uzyskać swój pierwszy ChannelMembership i

p.reload.channel_memberships.first 

ładunki bezpośrednio ze stowarzyszenia. Być może jakaś kombinacja ponownego załadowania niektórych elementów zapisanych w pamięci podręcznej (nie znam źródła AR) sygnalizuje powiązanie jako tylko do odczytu. Po zastosowaniu na nim zakresu limitu (1) może on resetować je w nowej relacji i działać zgodnie z oczekiwaniami.

Przeglądałbym ActiveRecord :: Persistence/Associations trochę więcej, aby uzyskać pełną odpowiedź.

+0

Tak, myślę, że byłby to dobry czas dla mnie, aby przeglądać AR i AREL. W każdym razie chciałbym się nauczyć, jak znaleźć drogę wokół źródła szyn. –