Davide Targa website

Programming, web development and open source

Paperclip Update Failure With Accepts_nested_attributes

I am using paperclip in a Rails 3.0.5 application.

I have the following models:

1
2
3
4
5
6
7
8
class Ad < ActiveRecord::Base
  belongs_to :category
  has_many :images, :dependent => :destroy
  accepts_nested_attributes_for :images,
                                :reject_if => lambda { |attr| attr[:image].blank? },
                                :allow_destroy => true
...
end

Every ad has many images. I manage images through paperclip gem. Here the model for Image:

1
2
3
4
5
6
7
8
9
10
11
12
class Image < ActiveRecord::Base
  belongs_to :ad
  has_attached_file :image,
                    :styles => {:thumb => "100x100>", :medium => "600x600>"}

  validates_attachment_size :image,
                            :less_than => 1.megabyte

  validates_attachment_content_type :image,
                                    :content_type => ['image/jpeg', 'image/png', 'image/gif']
...
end

The form for ad has a fields_for images. The standard update action in the ads controller should look like this:

1
2
3
4
5
6
7
8
9
10
11
12
class AdsController < ApplicationController
  ...
  def update
    @ad = Ad.find(params[:id])
    if @ad.update_attributes(params[:ad])
      redirect_to ad_path(@ad), :notice => t(:ad_update_ok)
    else
      render 'edit'
    end
  end
  ...
end

Unfortunately this doesn’t work because of a bug in this version of Rails. The update action updates the ad but doesn’t remove the related images if the _destroy attribute of the params hash is true.

After 2 hours of debugging and googling, I found a workaround to the problem. The solution is to add an “includes(:images)” method call before the find call inside the update action like shown below:

1
2
3
4
5
6
7
8
9
10
11
12
class AdsController < ApplicationController
  ...
  def update
    @ad = Ad.includes(:images).find(params[:id])
    if @ad.update_attributes(params[:ad])
      redirect_to ad_path(@ad), :notice => t(:ad_update_ok)
    else
      render 'edit'
    end
  end
  ...
end

Hope this helps.

Comments