2
votes

I am working with Rails 3 and Paperclip to attach uploaded files to several object types using a polymorphic association. I have created an Asset model and an inherited Image model (will be adding others, like Video and Documents later) as follows:

# app/models/asset.rb
class Asset < ActiveRecord::Base
  # Nothing here yet
end

# app/models/image.rb
class Image < Asset
  belongs_to :assetable, :polymorphic => true
  has_attached_file :file, {
    :styles => {
      :small => { :geometry => '23x23#', :format => 'png' },
      :medium => { :geometry => '100x100#', :format => 'png' } } 
  }.merge(PAPERCLIP_STORAGE_OPTIONS).merge(PAPERCLIP_STORAGE_OPTIONS_ASSET_IMAGE) # Variables sent in environments to direct uploads to filesystem storage in development.rb and S3 in production.rb
  validates_attachment_presence :file
  validates_attachment_size :file, :less_than => 5.megabytes
end

I then have another object type, Unit, which I am attaching multiple images to as follows:

# app/models/unit.rb
class Unit < ActiveRecord::Base
  # ...

  has_many :images, :as => :assetable, :dependent => :destroy
  accepts_nested_attributes_for :images

end

# app/controllers/units_controller.rb
class UnitsController < ApplicationController
  # ...

  def new
    @unit = current_user.units.new
    # ...
    @unit.images.build
  end

  def create
    @unit = current_user.units.new(params[:unit])
    # ...
    respond_to do |format|
      if @unit.save
        format.html { redirect_to(@unit, :notice => 'Unit creation successful!') }
      else
        format.html { render :action => "new" }
      end
    end
  end

  def show
    @unit = current_user.units.find(params[:id])
    @unit_images = @unit.images
    # ...
  end

  def edit
    @unit = current_user.units.find(params[:id])
    # ...
    @unit.images.build
  end

  def update
    @unit = current_user.units.find(params[:id], :readonly => false)

    respond_to do |format|
      if @unit.update_attributes(params[:unit])
        format.html { redirect_to(@unit, :notice => 'Unit was successfully updated.') }
      else
        format.html { render :action => "edit" }
      end
    end
  end

  def destroy
    @unit = current_user.units.find(params[:id])
    @unit.destroy

    respond_to do |format|
      format.html { redirect_to(units_url) }
    end
  end

end

# app/views/units/_form.html.haml
.field # Display already uploaded images
  = f.fields_for :images do |assets|
    - unless assets.object.new_record?
      = link_to(image_tag(assets.object.file.url(:medium)), assets.object.file.url(:original))
.field # Display field to add new image
  = f.fields_for :images do |assets|
    - if assets.object.new_record?
      = assets.label :images, "Image File"
      = assets.file_field :file, :class => 'uploadify'

Using these settings I am able to upload images one at at time, per display of the form.

The issues start when I try to integrate Uploadify to add multi file uploading/previewing. I have satisfied all the Uploadify dependancies, but in order to save the images associated with the Unit model I need to somehow include a reverence to the unit_id so that the polymorphic association can be made properly. Below is my current Uploadify code:

%script
  $(document).ready(function() {
    $('.uploadify').uploadify({
      uploader        : '/uploadify/uploadify.swf',
      cancelImg       : '/uploadify/cancel.png',
      auto            : true,
      multi           : true,
      script          : '#{units_path}',
      scriptData      : {
        "#{key = Rails.application.config.session_options[:key]}" : "#{cookies[key]}",
        "#{request_forgery_protection_token}" : "#{form_authenticity_token}",
      }
    });   
  });

So while I can easily upload with Paperclip along, Uploadify will not work. Any help would be much appreciated. Thank you in advance.


UPDATE:

After doing more research I ran across this comment to a similar issue: Rails3, S3, Paperclip Attachment as it's own model?. Any thoughts on whether or not that would work in this situation? Is there an easy way of determining the unit.id from the /new method and passing it to the Uploadify-created Asset?

1

1 Answers

4
votes

We had solved a very similar problem once by saving the model right away when loading the form in a draft state (using state machine). Like this the model is available when you're trying to attach the files you're uploading and once you're submitting the rest of the form, you're basically just updating the model which changes it's state to e.g. published. It's a little work to update the controllers etc., but it did the trick.