2011-08-19 24 views
5

Tôi có ba mô hình ActiveRecord: Đối tác, MembershipChannel (mà là một mô hình STI, kế thừa từ Channel) và ChannelMembership (tôi không chịu trách nhiệm về việc đặt tên các mô hình ...)Tại sao has_many của tôi thông qua hồ sơ liên quan (đôi khi) chỉ đọc?

Khi tôi tải một ChannelMembership thông qua sự liên kết đối tác, tôi đôi khi (!) kết thúc với một bản ghi chỉ đọc. Đây là trong Rails 3.0.9. Cùng một mã không hoạt động theo cách này trong 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 

Tại sao readonly? đúng khi first được kêu gọi hiệp hội, nhưng không phải trên các mối quan hệ từ limit?

Tôi hiểu rằng readonly được kích hoạt nếu tôi sử dụng đoạn SQL khi tìm bản ghi, nhưng đây không phải là trường hợp ở đây. Nó chỉ là một đồng bằng thông qua hiệp hội. Vấn đề phức tạp duy nhất là nó tham gia vào một mô hình STI. Hơn nữa, nhìn vào SQL được tạo ra từ hai ví dụ cuối cùng, chúng giống hệt nhau!

Tôi có thể nhận được hành vi mà tôi muốn bằng cách chỉ định :readonly => false về liên kết nhưng tôi muốn hiểu những gì đang diễn ra.

Không có phạm vi mặc định trên kênh, MembershipChannel hoặc ChannelMembership. Đây là tuyên bố hiệp hội trên Partner:

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

đây là SQL được tạo ra từ các bản ghi của tôi:

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 

Trả lời

2

tôi đã có thể để tái tạo vấn đề của bạn thông qua một has_many cơ bản: thông qua hiệp hội và cũng là để những gì gây ra nó.

Từ những gì tôi có thể nói, nó chỉ xảy ra khi phương thức tải lại được gọi trên đối tượng gốc. Tôi không chắc chắn nếu điều này là do bất cứ điều gì mà tải lại làm đặc biệt, hoặc có lẽ vì cờ thuộc tính nhất định đang được thiết lập lại?

Giả thuyết thứ hai của tôi là nó có cái gì để làm với thực tế là

p.reload.channel_memberships.limit(1) 

trả về một ActiveRecord :: Quan hệ thông qua đó bạn có được ChannelMembership đầu tiên của bạn, và

p.reload.channel_memberships.first 

tải nó trực tiếp từ hiệp hội. Có lẽ một số kết hợp của tải lại đặt lại một số mục được lưu trong bộ nhớ cache (Tôi không biết nguồn AR) đang gắn cờ liên kết là chỉ đọc. Khi bạn áp dụng giới hạn (1) phạm vi trên nó, nó có thể được đặt lại trong một mối quan hệ mới, và làm việc như bạn mong muốn.

Tôi muốn poke xung quanh ActiveRecord :: Persistence/Associations nhiều hơn một chút cho câu trả lời đầy đủ.

+0

Vâng, tôi nghĩ đây sẽ là thời điểm tốt để tôi khám phá xung quanh AR và AREL. Tôi đã có ý nghĩa để tìm hiểu làm thế nào để tìm cách của tôi xung quanh nguồn đường ray, anyway. –

Các vấn đề liên quan