乐者为王

Do one thing, and do it well.

Rails 2.3和Paperclip实现多图片上传

1
2
3
4
5
6
7
8
9
rails upload
cd upload
script/plugin install git://github.com/thoughtbot/paperclip.git
script/plugin install git://github.com/aaronchi/jrails.git
script/generate scaffold album name:string
script/generate model photo album:references
script/generate paperclip photo data
rake db:migrate
script/server

修改album.rb添加photo_attributes属性:

1
2
3
4
5
6
7
8
9
10
class Album < ActiveRecord::Base
  has_many :photos
  validates_presence_of :name

  def photo_attributes=(photo_attributes)
    photo_attributes.each do |attributes|
      photos.build(attributes)
    end
  end
end

修改photo.rb添加附件相关属性:

1
2
3
4
5
6
7
8
9
10
class Photo < ActiveRecord::Base
  belongs_to :album

  has_attached_file :data,
    :url => "/uploads/:style_:basename.:extension",
    :styles => { :thumb => "50x50#", :large => "640x480#" }
  validates_attachment_presence :data
  validates_attachment_content_type :data,
    :content_type => ['image/jpeg', 'image/jpg', 'image/png']
end

修改new.html.erb为以下代码:

1
2
3
4
5
6
7
8
<h1>New album</h1>

<% form_for @album, :html => { :multipart => true } do |f| %>
  <%= render :partial => 'form', :locals => { :f => f } %>
  <p><%= f.submit "Create" %></p>
<% end %>

<%= link_to 'Back', albums_path %>

对edit.html.erb做同样的修改:

1
2
3
4
5
6
7
8
9
<h1>Editing album</h1>

<% form_for @album, :html => { :multipart => true } do |f| %>
  <%= render :partial => 'form', :locals => { :f => f } %>
  <p><%= f.submit "Update" %></p>
<% end %>

<%= link_to 'Show', @album %> |
<%= link_to 'Back', albums_path %>

把从new.html.erb和edit.html.erb中抽取出来的代码保存为_form.html.erb文件:

1
2
3
4
5
6
<%= f.error_messages %>

<p>
  <%= f.label :name %>
  <%= f.text_field :name %>
</p>

然后在后面添加如下代码:

1
2
3
4
5
6
7
<div id="photos">
  <% if @album.new_record? %>
    <%= render :partial => 'photo', :collection => @album.photos %>
  <% end %>
</div>

<%= link_to_function "Add Photo" do |page| page.insert_html :bottom, :photos, :partial => 'photo', :object => Photo.new end %>

创建_photo.html.erb文件,代码如下:

1
2
3
4
5
6
7
8
9
<div class="photo">
  <p>
  <% fields_for "album[photo_attributes][]", photo do |p| %>
    <%= p.label :photo %><br />
    <%= p.file_field :data, :index => nil %>
    <%= link_to_function "delete", "remove_field($(this), ('.photo'))" %>
  <% end %>
  </p>
</div>

再在application.js中添加下列代码,这样就可以删除file字段了。

1
2
3
function remove_field(element, item) {
  element.up(item).remove();
}

然后修改albums_controller.rb中的new方法:

1
2
3
4
5
6
7
8
def new
  @album = Album.new
  1.upto(3) { @album.photos.build }

  respond_to do |format|
    format.html # new.html.erb
  end
end

这样,上传多文件的功能基本就完成了。下面就来实现显示和修改的功能。

在show.html.erb的末尾添加下列代码,上传成功后用来显示图片:

1
2
3
4
#loop through the albums photos
<% for photo in @album.photos %>
  <%= image_tag photo.data.url(:thumb) %>
<% end %>

修改albums_controller.rb中的edit和update方法,用来删除图片:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def edit
  @album = Album.find(params[:id])
  if @album.photos.first.nil?
    1.upto(3) { @album.photos.build }
  end
end

def update
  params[:photo_ids] ||= []
  @album = Album.find(params[:id])
  unless params[:photo_ids].empty?
    Photo.destroy_pics(params[:id], params[:photo_ids])
  end

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

在photo.rb中加上下面的代码:

1
2
3
def self.destroy_pics(album, photos)
  Photo.find(photos, :conditions => { :album_id => album }).each(:destroy)
end

然后新建_album_photo.html.erb,代码如下:

1
2
3
4
<% unless album_photo.new_record? %>
  <%= image_tag album_photo.data.url(:thumb) %>
  <%= check_box_tag "photo_ids[]", album_photo.id %>
<% end rescue nil %>

接着在_form.html.erb中加入下面的代码就可以删除图片了:

1
2
3
<div class="album_photos">
  <%= render :partial => 'album_photo', :collection => @album.photos %>
</div>

Comments