don_Bigote
don_Bigote

Reputation: 947

What is the correct way to update images with has_many_attached in Rails 6

I have a Rails 6 app that uses Active Storage to store multiple images to a model (Activity) with has_many_attached.

I don't understand how to append extra images instead of replacing the existing images. When I upload images the first time they save correctly. However, when I update the record, and I add a new image, the previous images are replaced by the new image. In Rails 5 the new image would be appended without replacing the previously saved images.

How do I append a new image instead of replacing the previous images?

I have an Activity model that has the following:

has_many_attached :images

In the form I have:

<%= f.file_field :images, multiple: true %>

In the controller I have the following:

def update
  @activity = Activity.find(params[:id])

  if @activity.update(activity_params)
    flash[:success] = "Saved"
    redirect_to activity_path(@activity)
  else
    flash[:error] = "Not saved"
    redirect_to edit_activity_path(@activity)
  end
end

private

  def activity_params
    params.require(:activity).permit(:name, images:[])
  end

Upvotes: 13

Views: 11036

Answers (4)

Elias Glyptis
Elias Glyptis

Reputation: 530

Replacing images is not desirable at all

This is the dafault behaviour in rails 6.

A better solution

Make sure to make a strong note of this in your readme.txt or in your commit.

You can add this in application.rb but better off to create a file in initiallizers/active_storage.rb. (it makes more sense) and more organized.

#initiallizers/active_storage.rb

Rails.application.config.active_storage.replace_on_assign_to_many = false

or you can open application.rb

config.active_storage.replace_on_assign_to_many = false

This setting ensures that new attachments are added to existing ones rather than replacing them.

Upvotes: 0

Max Berdnikau
Max Berdnikau

Reputation: 83

This happens cause assigning to attachments declared with has_many_attached since Rails 6.0 replaces any existing attachments by default.

Details:

So, in Rails 6.0+ you need to add this line to your environment config (config/environments/development.rb, etc.):
config.active_storage.replace_on_assign_to_many = false
After app restart previously added attachments won't be replaced.

Upvotes: 2

don_Bigote
don_Bigote

Reputation: 947

This is the solution that I have now:

Add this to the update action:

if params[:activity][:images].present?
  params[:activity][:images].each do |image|
  activity.images.attach(image)
end

So, the entire update action looks like this:

def update
  if activity.update(activity_params)
    if params[:activity][:images].present?
      params[:activity][:images].each do |image|
        activity.images.attach(image)
      end
    end
    flash[:success] = 'Updated!'
    respond_with activity, location: activity_path(activity)
  else
    flash[:error] = 'Not updated'
    respond_with activity, location: activity_path(activity)
  end
end

And remove this from permitted params:

images:[]

Upvotes: 20

Sumra Yasmin
Sumra Yasmin

Reputation: 9

Try selecting multiple files like this https://i.sstatic.net/EqaU7.png If it works then you will need to select all previous images while uploading new one which does not sound good. You may like to use nesting forms.

Upvotes: -5

Related Questions