DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

William has posted 8 posts at DZone. View Full User Profile

Multiple Upload Using Attachment_fu

06.02.2009
| 6475 views |
  • submit to reddit
        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 %>
  ...
  <p>
    <%= label :task, :photo, 'Photos' %><br />
    <%= file_field_tag 'photo_file[]' %><br />
    <%= file_field_tag 'photo_file[]' %>
  </p>
  ...

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.    

Comments

William Notowidagdo replied on Wed, 2007/08/15 - 10:34pm

@miss_moviestar please provide more details on your problem? Thanks.

Snippets Manager replied on Wed, 2009/07/29 - 8:00am

hey i have a problem i got the error uninitialized constant TasksController::TaskService what should i do? thx