Reputation: 489
So I am building an associated object through a main object like so:
item.associated_items.build({name: "Machine", color: "Grey"})
and then in another method calling item.save
. However I am getting an ActiveRecord::ReadOnlyRecord
error. I read in the docs that
Records loaded through joins with piggy-back attributes will be marked as read only since they cannot be saved.
so I think that is what is happening here. But
I dont't know why that is happening. I have called save on an object with a new associated record before and had no problems.
What do the docs mean when they say "piggy-back attributes"?
Is there a way to make the save happen by doing something like item.associated_items.readonly(false).build(attributes)
. I tried that and it didnt work, but I'm hoping there is another way.
edit: I just tried
new_associated_item = AssociatedItem.new({attributes})
item.associated_items << new_associated_item
and the later method calls
item.save
and the read only exception still happens.
edit2: MurifoX asked me about how Item is being loaded. The above code is happening in a couple of service objects. The process is
Controller
owner = Owner.includes(:medallions).references(:medallions).find_by_id(params[:id])
later
creator = NoticeCreator.new(owner)
creator.run
NoticeCreator
def initialize #effectively
medallion_notice_creators = []
owner.medallions.some_medallion_scope.each do |medallion|
medallion_notice_creator = MedallionNoticeCreator.new(medallion)
medallion_notice_creator.prepare
medallion_notice_creators << medallion_notice_creator
end
end
later after looping through the medallion notice creators
def prepare
medallion.notices.build(attributes)
end
later
medallion_notice_creators.each do |medallion_notice_creator|
medallion_notice_creator.medallion.save
end
Apologies if the code seems convoluted. There is a bunch of stuff going on and I'm trying to condense the code and anonymize it.
Upvotes: 4
Views: 3440
Reputation: 15089
Objects created with joins
or includes
, which is your case, are marked read-only because you are making a giant query with joins and stuff and preloading nested objects within your main one. (ActiveRecord
can become confused with so many attributes and don't know how to build the main object, so it marks readonly
on it.)
As you have noticed, this won't happen if you create you object with a simple find
, as the only attributes received from the query are from the object itself.
I don't know why you are eager loading all of this associations, maybe it is from some rule in your code, but you should try to create a simple owner
object using Owner.find(params[:id])
, and lazy loading the associations when needed, so this way you can build nested associations on the simple object and save them.
Upvotes: 3