When I create a Blog
object, both the create
and update
callbacks are triggered in sequence.
In this case, updating the Blog
object deletes all existing images
and generates new ones. I want to only generate new images
on create
, and delete and re-create them on update
.
I think it's due to the nested object via accepts_nested_attributes_for
, but I can't seem to find a working alternative.
Is this a Rails bug? How can I force the correct callbacks to only trigger once per action?
class Blog
has_many :posts
has_many :images
accepts_nested_attributes_for :posts
after_update :destory_existing_images, if: -> { images.any? }
after_commit :create_images, on: [:update, :create], if: -> { images.none? }
private
def destory_existing_images
images.destroy_all
end
def create_screenshots
images.create!(tag: title)
end
end
CodePudding user response:
It would be better if you use separate callbacks. Use after_create_commit
for initialization and after_update_commit
to update the images.
You could also check if the title changed before you update your images. Dirty API is great for that, your condition then would look like if: -> { images.any? && saved_change_to_title? }
.
Solution
class Blog
has_many :posts
has_many :images
accepts_nested_attributes_for :posts
after_create_commit :create_images, if: -> { images.none? }
after_update_commit :update_images, if: -> { images.any? && saved_change_to_title? }
private
def update_images
images.destroy_all
images.create!(tag: title)
end
def create_images
images.create!(tag: title)
end
end