Over a million developers have joined DZone.

Multiple Upload Using Attachment_fu

·
Here is my case, I got a simple Task (to-do) list app where you can upload up to 2 photo images for each task. Obviously you will need attachment_fu installed on your Rails app before continue.

Task model

class Task < ActiveRecord::Base
  has_many :photos, :dependent => :destroy  
  validates_presence_of :description
end


Photo model

class Photo < ActiveRecord::Base
  belongs_to :task  
  has_attachment :content_type => :image,
                 :storage      => :file_system,
                 :max_size     => 500.kilobytes,
                 :resize_to    => '384x256',
                 :thumbnails   => {
                   :large  => '96x96>',
                   :medium => '64x64>',
                   :small  => '48x48>'
                 }
  validates_as_attachment               
end


TaskService model

class TaskService
  attr_reader :task, :photo
  
  def initialize(task, photos)
    @task = task
    @photos = photos
  end
  
  def save
    return false unless valid?
    begin
      Task.transaction do
        @photos.each do |photo|
          if photo.new_record?
            @task.photo.find(photo).destroy if @task.photos.include?(photo)
            photo.task = @task
            photo.save!
          end
        end  
        @task.save!
        true
      end
    end
  end
  
  def update_attributes(task_attributes, photo_file)
    @task.attributes = task_attributes
    unless photo_file.nil?
      @photos = []
      photo_file.each do |file|
        @photos << Photo.new(:uploaded_data => file)
      end
    end
    save
  end
  
  def valid?    
    @task.valid? && valid_photos?
  end
  
  def valid_photos?
    @photos.each do |photo|
      return false unless photo.valid?
    end
    true
  end
end


New / edit task view

<% form_for(@task, :html => { :multipart => true }) do |f| %>
  <%= error_messages_for :task, :photo %>
  ...
  

<%= label :task, :photo, 'Photos' %>
<%= file_field_tag 'photo_file[]' %>
<%= file_field_tag 'photo_file[]' %>

...
Tasks controller ... def create @task = Task.new(params[:task]) build_photos(params[:photo_file]) @service = TaskService.new(@task, @photos) respond_to do |format| if @service.save flash[:notice] = 'New Task created.' format.html { redirect_to(@task) } format.xml { render :xml => @task, :status => :created, :location => @task } else format.html { render :action => "new" } format.xml { render :xml => @task.errors, :status => :unprocessable_entity } end end end def update @task = Task.find(params[:id]) @photos = @task.photos @service = TaskService.new(@task, @photos) respond_to do |format| if @service.update_attributes(params[:task], params[:photo_file]) flash[:notice] = 'Task was successfully updated.' format.html { redirect_to(@task) } format.xml { head :ok } else format.html { redirect_to(tasks_url) } format.xml { render :xml => @task.errors, :status => :unprocessable_entity } end end end ... protected def build_photos(photo_file) @photos = [] photo_file.each do |file| @photos << Photo.new(:uploaded_data => file) unless file.blank? end end I believe this snippet need some refactoring, but I hope you find it useful enough.
Topics:

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}