Hello folks,

It’s been a while since I updated the blog and rails has changed a bit since then. I thought I’d revise one of my previous posts: the one about uploading multiple images using paperclip. This time we’re going to be doing it using Rails 2.3.4. I’m going to be using the paperclip gem, as well as the nifty_generator gem(for ease of demonstration). Just google them if you don’t know what they are or if you’re new to the rails world ;)

Lets start off by installing the necessary gems.

gem sources -a http://gems.github.com
sudo gem install thoughtbot-paperclip
sudo gem install gem install nifty-generators

Create our Rails app and generate a few things for us to play with.

rails demo
# remove index file from the public directory
 
script/generate nifty_layout
script/generate nifty_scaffold Album name:string
 
# config/routes.rb
map.root :controller => 'albums'
 
script/generate model Photo album_id:integer
script/generate paperclip photo data
rake db:migrate
script/server

Now open up the form partial in app/views/albums and modify it like so.

<% form_for @album, :html => { :multipart => true } do |f| %>
  <%= f.error_messages %>
  <p>
    <%= f.label :name %><br />
    <%= f.text_field :name %>
  </p>	
  <div id="photos">
     <% if @album.new_record? %>
       <%= render :partial => 'photo', :locals => { :form => f, :photo => @album.photos.build } %>
    <% end %>
  </div>
  <%= add_object_link("New Photo", f, @album.photos.build, "photo", "#photos") %>
  <p><%= f.submit "Submit" %></p>
<% end %>

Then add a new partial under app/views/albums called photo:

<div class="photo">
  <p>
  <% form.fields_for :photos, photo, :child_index => (photo.new_record? ? "index_to_replace_with_js" : nil) do |photo_form| %>    
    <%= photo_form.file_field :data %>
    <%= link_to_function "delete", "remove_field($(this), ('.photo'))" %><br/>
  <% end %>
  </p>
</div>

Add the necessary Javascript methods so that we can generate photo file upload fields.

# in application.js
function remove_field(element, item) {
  element.up(item).remove();
}
 
# download the jquery library to your javascripts folder and then modify application.html.erb layout file.
<head>
  <title><%= h(yield(:title) || "Untitled") %></title>
  <%= stylesheet_link_tag 'application' %>
  <%= javascript_include_tag :defaults, 'jquery-1.3.2.min' %>
  <script>
     jQuery.noConflict();
   </script>
   <%= yield(:head) %>
</head>

Add the following helper methods to albums_helper.rb. This bit was modified from apidock, rails, fields_for section.

  def add_object_link(name, form, object, partial, where)
    html = render(:partial => partial, :locals => { :form => form}, :object => object)
    link_to_function name, %{
      var new_object_id = new Date().getTime() ;
      var html = jQuery(#{js html}.replace(/index_to_replace_with_js/g, new_object_id)).hide();
      html.appendTo(jQuery("#{where}")).slideDown('slow');
    }
  end
 
  def js(data)
    if data.respond_to? :to_json
      data.to_json
    else
      data.inspect.to_json
    end
  end

Now add the following to your models.

# photo class
require 'paperclip'
 
class Photo < ActiveRecord::Base
  belongs_to :album
 
  has_attached_file :data, :styles => { :medium => "300x300>", :thumb => "100x100>" }
  validates_attachment_content_type :data, :content_type => 'image/jpeg', :message => "has to be in jpeg format"
end
 
# album class
class Album < ActiveRecord::Base
  attr_accessible :name
  validates_presence_of :name
  has_many :photos, :dependent => :destroy
 
  accepts_nested_attributes_for :photos
end

Notice the accepts_nested_attributes_for in the album class? That pretty much takes care of a plethora of code we would otherwise have to add to facilitate nested model behavior.

Now add this to your show.html.erb under apps/views/albums and you’re done.

<% title "Album" %>
 
<p>
  <strong>Name:</strong>
  <%=h @album.name %>
</p>
 
<% for photo in @album.photos %>
  <p><%= image_tag(photo.data(:thumb)) %></p>
<% end %>
 
<p>
  <%= link_to "Edit", edit_album_path(@album) %> |
  <%= link_to "Destroy", @album, :confirm => 'Are you sure?', :method => :delete %> |
  <%= link_to "View All", albums_path %>
</p>

That’s it folks. Enjoy and feel free to ask any questions or drop any comments!

Tagged with:
 

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">