利用paperclip实现图片上传

现在rails上最火的两大上传图片插件是fleximage与paperclip。如果单是处理图片,一气呵成的话,当然是fleximage,但如果还要上其他mp3,flv等附件,做成多态关联,那就选paperclip。嘛,在一般的功能上,paperclip还是比老一辈的上传插件要优胜不少,如什么acts_as_attachment,attachment_fu,还是更轻量化的file_column。

安装支持

本插件要有Rmagick与ImageMagick的外部支持,安装请参照我的另一篇文章

安装paperclip


ruby script/plugin install git://github.com/thoughtbot/paperclip.git

打造主体框架

这里涉及到两个模块,User与Photo。 我们是利用user_id来区分相册。


mysql > create database album_development;

rails album -d mysql

cd album 

ruby script/plugin install git://github.com/technoweenie/restful-authentication.git

ruby script/generate authenticated user sessions 

ruby script/generate scaffold Photo user:belongs_to is_avatar:boolean

自己配置config目录下的database.yml的用户名与密码。

接着下来的一步非常关键,我们要给Photo添加上传附件的能力。


ruby script/generate paperclip Photo image

rake db:migrate

我们把附件的名字命名为image,这样Paperclip就会给我们Photo模型增加四个前缀为<attachment>_(我们刚才给予的附件的名字)的属性(<attachment> _file_name , <attachment> _file_size ,<attachment> _content_type ,与<attachment> _updated_at),也就是image_file_name,image_file_size,image_content_type与image_updated_at。

删除public目录下的index.html,并添加路由规则:


map.root :users

修改users_controller,添加index action


def index;end

添加对应视图


<%= link_to "相册",photos_path %>

修改_user_bar.html.erb


<div id="user_bar">

  <% if logged_in? %>

    <%= link_to "注销",logout_path, :title => "注销"  %>

    <%= link_to "欢迎,<strong>#{current_user.login}</strong>",current_user %>

  <% else %>

    <%= link_to "登录",  login_path, :title => "登录"  %>

    <%= link_to "注册", signup_path, :title => "注册"  %>

  <% end %>

</div>

添加全局模板application.html.erb与全局助手layout_helper.rb


<!DOCTYPE html>

<html dir="ltr" lang="en-US">

  <head>

    <meta charset="utf-8"> <!-- simplified version; works on legacy browsers -->

    <%= javascript_include_tag :defaults  %>

    <title><%= h(yield(:title) || controller.action_name ) %></title>

    <%= stylesheet_link_tag 'blueprint','application' %>

    <%= yield(:head) %>

  </head>

  <body>

    <div id="container">

      <%- flash.each do |name, msg| -%>

        <%= content_tag :div, msg, :class => "#{name}" %>

      <%- end -%>

      <%- if show_title? -%>

        <h1><%=h yield(:title) %></h1>

      <%- end -%>

      <%= render :partial => "users/user_bar" %>

      <%= yield %>

    </div>

  </body>

</html>


module LayoutHelper

  def title(page_title, show_title = true)

    @content_for_title = page_title.to_s

    @show_title = show_title

  end



  def show_title?

    @show_title

  end

end

修改application_controller


class ApplicationController < ActionController::Base

  include AuthenticatedSystem

  #令views能够调用各自的视图助手(helper)里的方法

  helper :all

  #令以下方法能在所有helper,views,controller中调用(来自restful-authentication插件)

  helper_method :logged_in?, :current_user

  #开启反CSRF (Cross-Site Request Forgery)攻击保护

  protect_from_forgery

  #过滤敏感字段

  filter_parameter_logging :password, :password_confirmation

  #发生错误时自动重定向页面

  rescue_from ActiveRecord::RecordNotFound, :with => :record_not_found 

  protected



  def record_not_found

    render :file => File.join(RAILS_ROOT, 'public', '404.html'), :status => 404

  end

end

启动服务器,新建一名为司徒正美的用户,我们需要用其ID。

利用paperclip实现图片上传

修改Photo模块,实现上传能力

新建_form.html.erb


<% form_for @photo, :html => { :multipart => true } do |f| %>

  <%= f.error_messages %>

  <% if logged_in? %>

    <%= f.hidden_field :user_id,:value => current_user.id %>

  <% end %>

  <p>

    <%= f.label :is_avatar %><br />

    <%= f.check_box :is_avatar %>

  </p>

  <p>

    <%= f.file_field :image %>

  </p>

  <p>

    <button type="submit"><%= button_name  %></button>

  </p>

<% end %>

修改new.html.erb


<% title "上传图片" %>

<%= render :partial => 'form',:locals => {:button_name => "上传"}   %>

<%= link_to 'Back', photos_path,:class => "button" %>

修改show.html.erb


<div class="figure">

  <%= image_tag @photo.image.url ,:alt =>"被GFW和谐了!" %>

  <div class="legend">所有人:<%=h @photo.user.login %>;是否为头像:<%= @photo.is_avatar %></div>

</div>

<%= link_to '编辑', [:edit,@photo],:class => "button" %>

<%= link_to '返回', photos_path,:class => "button"   %>

修改photo.rb


class Photo < ActiveRecord::Base

  belongs_to :user

  has_attached_file :image

end

这样它就可以运行了,非常简单!

利用paperclip实现图片上传

通过url上传图片


ruby script/generate migration AddImageRemoteUrlToPhoto image_remote_url:string

rake db:migrate

修改Photo模型


require 'open-uri'

class Photo < ActiveRecord::Base

  belongs_to :user

  

  has_attached_file :image



  attr_accessor :image_url

  before_validation :download_remote_image, :if => :image_url_provided?



  validates_presence_of :image_remote_url, :if => :image_url_provided?, :message => '地址不合法'



  private

  def image_url_provided?

    !self.image_url.blank?

  end



  def download_remote_image

    self.image = do_download_remote_image

    self.image_remote_url = image_url

  end



  def do_download_remote_image

    io = open(URI.parse(image_url))

    def io.original_filename; base_uri.path.split('/').last; end

    io.original_filename.blank? ? nil : io

  rescue # catch url errors with validations instead of exceptions (Errno::ENOENT, OpenURI::HTTPError, etc...)

  end

end

修改_form.html.erb


<% form_for @photo, :html => { :multipart => true } do |f| %>

  <%= f.error_messages %>

  <% if logged_in? %>

    <%= f.hidden_field :user_id,:value => current_user.id %>

  <% end %>

  <% if action_name == "new" %>

    <p>

      <%= f.label :is_avatar,"是否作为头像" %>

      <%= f.check_box :is_avatar %>

    </p>

  <% end %>

  <p>

    <%= f.file_field :image %><br />

    或者通过URL<%= f.text_field :image_url %>

  </p>

  <p>

    <button type="submit"><%= button_name  %></button>

  </p>

<% end %>

利用paperclip实现图片上传

一样上传成功!

利用paperclip实现图片上传

添加多种样式与验证


#……………………

 has_attached_file :image,

    :default_url   => "/images/rails.png",

    :styles => {

    :thumb=> "100x100#",

    :gallery  => "150x150>" ,

    :avatar =>  "200x200>"}

  #使用这个就不能删除图片了

  #validates_attachment_presence :image

  validates_attachment_size :image, :less_than => 5.megabytes

  validates_attachment_content_type :image, :content_type => [ 'image/gif', 'image/png', 'image/x-png', 'image/jpeg', 'image/pjpeg', 'image/jpg']

#……………………

删除图片

由于paperclip默认是把上传的东西保存在硬盘中的,调用destroy action只能删除数据库的数据,但不能删除其关的图片。因此我们需要在其模型中添加删除图片的逻辑。


  #=============================其他代码=====================

  #=============================删除图片=====================

  def delete_image=(value)

    @delete_image = !value.to_i.zero?

  end



  def delete_image

    !!@delete_image

  end

  alias_method :delete_image?, :delete_image

  before_validation :clear_image

 

  def clear_image

    self.image = nil if delete_image? && !image.dirty?

  end

#===============================其他代码===================

修改_form.html.erb


<% form_for @photo, :html => { :multipart => true } do |f| %>

  <%= f.error_messages %>

  <% if logged_in? %>

    <%= f.hidden_field :user_id,:value => current_user.id %>

  <% end %>

  <% if action_name == "new" %>

    <p>

      <%= f.label :is_avatar,"是否作为头像" %>

      <%= f.check_box :is_avatar %>

    </p>

  <% end %>

  <p>

    <%= f.file_field :image %><br />

    或者通过URL<%= f.text_field :image_url %>

  </p>

  <%- unless @photo.new_record? || [email protected]? -%>

    <div>

      <%= image_tag(@photo.image.url(:gallery), :alt => 'Photo', :title => '当前图片') %>

      <p>

        <%= f.label(:delete_image, '删除图片') %>

        <%= f.check_box(:delete_image) %>

      </p>

    </div>

  <%- end -%>

  <p>

    <button type="submit"><%= button_name  %></button>

  </p>

<% end %>

修改edit.html.erb


<% title "编辑图片" %>

<%= render :partial => 'form',:locals => {:button_name => "更新"}   %>

<%= link_to '大图', @photo,:class => "button" %>

<%= link_to '返回', photos_path,:class => "button" %>

修改update action


  def update

    @photo = Photo.find(params[:id])

    if @photo.update_attributes(params[:photo])

      message = @photo.delete_image?? "删除图片成功!" : "更新图片成功!"

      flash[:notice] = message

      redirect_to(@photo)

    else

      render :action => "edit" 

    end

  end


<h1>Listing photos</h1>



<table>

  <tr>

    <th>所有人</th>

    <th>是否作为头像</th>

    <th>预览</th>

  </tr>



<% @photos.each do |photo| %>

  <tr>

    <td><%=h photo.user.login %></td>

    <td><%= photo.is_avatar? "是":"否" %></td>

    <td><%= image_tag photo.image.url(:thumb) ,:alt =>"被GFW和谐了!" %></td>

    <td><%= link_to 'Show', photo %></td>

    <td><%= link_to 'Edit', edit_photo_path(photo) %></td>

    <td><%= link_to 'Destroy', photo, :confirm => 'Are you sure?', :method => :delete %></td>

  </tr>

<% end %>

</table>



<br />



<%= link_to 'New photo', new_photo_path %>

利用paperclip实现图片上传

最后,paperclip是对window不友好的,google讨论组中最常见的问题是“is not recognized by the 'identify' command”错误,不过我在写这篇博文时还是没遇见过。它在LINUX环境是绝对没有问题的。

你可能感兴趣的:(Paperclip)