File Upload

Using acts_as_attachment; see also attachment_fu, file_column

  1. Install acts_as_attachment
  2. script/plugin source http://svn.techno-weenie.net/projects/plugins
    script/plugin install acts_as_attachment
    

  3. Create a model for storing photos
  4. script/generate attachment_model photo

    edit the generated migration

    
    class CreatePhotos < ActiveRecord::Migration
      def self.up
        create_table :photos do |t|
          t.column "coffee_house_id", :integer, :null => false
          t.column "content_type", :string
          t.column "filename", :string     
          t.column "size", :integer
          
          # used with thumbnails, always required
          t.column "parent_id",  :integer 
          t.column "thumbnail", :string
          
          # required for images only
          t.column "width", :integer  
          t.column "height", :integer
    
          # required for db-based files only
          #t.column "db_file_id", :integer
        end
    
        # only for db-based files
        # create_table :db_files, :force => true do |t|
        #      t.column :data, :binary
        # end
      end
    
      def self.down
        drop_table :photos
        
        # only for db-based files
        # drop_table :db_files
      end
    end
    

    run migration

    rake db:migrate

    edit the generated model

    class Photo < ActiveRecord::Base
      belongs_to :coffee_house
      acts_as_attachment :storage => :file_system, :content_type => :image, :thumbnails => {:normal => '300', 'thumb' => '75'}
      validates_as_attachment
    end
    

  5. Create controller actions and views
  6. add actions to coffee_house_controller

    
      def new_photo
        @photo = Photo.new(:coffee_house_id=>params[:id])
      end
    
      def create_photo
        @photo = Photo.new(params[:photo])
        if @photo.save
          redirect_to :action => 'show', :id => @photo.coffee_house_id
        else
          render :action => 'new_photo'
        end
      end
    
      def destroy_photo
        @photo = Photo.find_by_id(params[:id])
        redirect_to :action => 'index' and return unless @photo
        @coffee_house = @photo.coffee_house
        @photo.destroy
        render :action => 'show'
      end
    

    GETs should be safe - update for new actions (find this snippet in coffee_house_controller.rb and add the bolded action names)

    
      # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
      verify :method => :post, :only => [ :destroy, :create, :update, :create_photo, :destroy_photo ],
             :redirect_to => { :action => :list }
    

    create view in app/views/coffee_house/new_photo.rhtml

    
    <h1>New photo</h1>
    <%= error_messages_for :photo %>
    <% form_for :photo, :url => { :action => 'create_photo' }, :html => { :multipart => true } do |f| -%>
      <p><%= f.hidden_field :coffee_house_id %></p>
      <p><%= f.file_field :uploaded_data %></p>
      <p><%= submit_tag :Create %></p>
    <% end -%>
    

  7. Integrate with the CoffeeHouse application
  8. Add relation to app/models/coffee_house.rb

    has_many :photos, :dependent => :destroy

    Add a gallery and new photo link to app/views/coffee_house/show.rhtml

    
    <% for column in CoffeeHouse.content_columns %>
    <p>
      <%= column.human_name %>: <%=h @coffee_house.send(column.name) %>
    </p>
    <% end %>
    
    <% for photo in @coffee_house.photos -%>
      <p><%= photo.filename %></p>
      <%= image_tag photo.public_filename('thumb') %>
      <%= image_tag photo.public_filename, :size => photo.image_size %>
    <% end -%>
    
    <p><%= link_to 'Add photo', :action => 'new_photo', :id => @coffee_house %></p>
    
    
    <%= link_to 'Edit', :action => 'edit', :id => @coffee_house %> |
    <%= link_to 'Back', :action => 'list' %>
    

  9. File storage
    • create directory public/photos
    • make it recursively writeable for the web server

  10. RMagick integration
  11. add at the end of config/environment.rb: require 'RMagick'