`
a420144030
  • 浏览: 83662 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

图片上传插件 Paperclip

阅读更多

官网:http://thewebfellas.com/blog/2008/11/2/goodbye-attachment_fu-hello-paperclip

 

以前大家可能一直在用attachment_fu上传文件,现在有一个非常方便上传图片的插件Paperclip, 该插件和ImageRmagick结合使用可以设定图片大小等多种功能,同时使用起来也非常方便。下面是具体的使用步骤:

  1. 安装插件

     

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

 

   你也可以在GitHub 下载到该插件

 

     2.   下载ImageMagick

          ImageMagick :  http://www.imagemagick.org/script/binary-releases.php#windows

          Rmagick.gem :  http://rubyforge.org/frs/?group_id=12&release_id=26026

     3.  

Discarding an uploaded image

When an image file is uploaded Paperclip stores it using the original style name. While it isn’t possible to tell Paperclip to simply discard the original image, it is possible to define your own original style which Paperclip will then use. As an example, if your model contains the following:

has_attached_file :photo, 
                  :styles => { :original => '250x250>', 
                               :small => '50x50' }

 

Then even if a huge photo (say 1600x1600) is uploaded, it won’t be stored on your server (or S3 bucket). You will however still have an original file but it will have been resized to 250x250, helping to reduce the amount of storage space needed for attachments.

 

Styles can be Procs too

Most of the time you’ll probably be passing geometry strings for the has_attached_file :styles option, but a very nice feature is the ability to also pass a Proc to provide dynamic geometry string generation. For example, you might have a model that has photo_width and photo_height attributes that can be specified by the user and you want to generate a ‘custom’ thumbnail that uses these dimensions. Paperclip allows you to do this easily:

has_attached_file :photo, 
                  :styles => { :original => '250x250>', 
                               :small => '50x50', 
                               :custom => Proc.new { |instance| "#{instance.photo_width}x#{instance.photo_height}>" } }

 

As you can see the Proc receives the object that the attachment is part of as a parameter and returns a geometry string generated using the photo_width and photo_height attributes. Adding a call to the reprocess! method of the attachment object in your model’s before_save callback also allows you to regenerate the thumbnails if either of these attributes are updated.

Rename files on upload

The has_attached_file :url and :path options can be used to customise the name of your attachments: :url defines the URL that will be used by things like image_tag to access your image and allows you to either provide direct access to the image or to route access through a controller (to provide permission checking for example) and :path determines where the image file is stored either on your server (for file system storage) or in an S3 bucket.

Both options use interpolation, allowing you to use special tags that will be replaced with actual values at runtime (just like regular Ruby string interpolation). The default interpolations provided by the plugin are:

:rails_root
The path to the Rails application.
:rails_env
The current environment (e.g. development, production)
:class
The class name of the model that the attachment is part of, underscored and pluralised for your convenience.
:basename
The name of the originally uploaded file without its extension.
:extension
The file extension of the originally uploaded file.
:id
The ID of the model that the attachment is part of.
:id_partition
The same as :id but formatted as a string using ID partitioning.
:attachment
The name of the attachment attribute (defined in the call to has_attached_file) downcased and pluralised for your enjoyment.
:style
The current style of the attachment file being processed (e.g. in the ‘discarding an uploaded image‘ example above the :style would be one of ‘original’ or ‘small’)

The default :url and :path options for has_attached_file are:

 

:url => "/:attachment/:id/:style/:basename.:extension"
:path => ":rails_root/public/:attachment/:id/:style/:basename.:extension"

 

Let’s say you’d prefer your users’ photos to be stored in a single ‘photos’ subdirectory of the public/images folder on your server using the user ID and style as the base file name. Your model would need to contain something like this:

has_attached_file :photo,
                  :url => "/images/:attachment/:id_:style.:extension",
                  :path => ":rails_root/public/images/:attachment/:id_:style.:extension"

 

If you want to hide images behind a controller do something like this:

has_attached_file :photo,
                  :url => "/:class/:id/:attachment/:style.:extension",
                  :path => ":rails_root/attachments/:class/:id/:attachment/:style.:extension"

 In this example the URL points to a PhotosController nested within the User resource (an example URL would be /users/2/photos/small.png) and the attachment files are stored outside of the public root in a subdirectory of an attachments folder (e.g. RAILS_ROOT/attachments/users/2/photos/small.png). The show action of the PhotosController would be responsible for returning the binary data of the appropriate file using the :style, :extension and :user_id parameters.

Custom interpolations

In addition to the predefined interpolations described above, Paperclip makes it very easy to define your own. For example one of my models has a symbol attribute that I want to use in the file name of images attached to it, so in a Rails initializer I add the following code:

Paperclip::Attachment.interpolations[:symbol] = proc do |attachment, style|
  attachment.instance.symbol.downcase
end

 

Interpolations are Procs that take two parameters, the attachment object and the current style, and it is possible to access the model that the attachment is part of using the instance attribute of the attachment object.

After adding my custom interpolation I can then use it like this:

has_attached_file :logo,
                  :url => '/:attachment/:symbol/:style/:basename.:extension',
                  :path => ':rails_root/public/:attachment/:symbol/:style/:basename.:extension '

 

Deleting an existing attachment

Deleting an existing attachment from a model is as simple as setting the attachment attribute to nil. In a RESTful world you could do this from the destroy action of a controller that maps to the attachment (for example using a DELETE request on /users/1/photos).

You can also quite easily replace an existing attachment by POSTing a new file to your update action. Things get a little trickier if you want to be able to delete an existing attachment without replacing it using an update action.

The approach I’ve used is to add a checkbox to the edit form that when checked causes any existing attachment to be removed unless a new file has also been selected in the file upload box. Here’s the view code:

<% form_for(user, :html => { :multipart => true }) do |f| %>
  <%# lots of exciting form fields %>
  <div>
    <%= f.label(:photo, 'Upload photo') %>
    <%= f.file_field(:photo) %>
  </div>
  <%- unless user.new_record? || !user.photo? -%>
    <div>
      <%= f.label(:delete_photo, 'Delete photo') %>
      <%= image_tag(user.photo.url, :alt => 'Photo', :title => 'Current photo') %>
      <%= f.check_box(:delete_photo) %>
    </div>
  <%- end -%>
  <%# lots more exciting form fields %>
<% end %>

 

This adds a checkbox, using an instance variable to track its value, if the user isn’t new and already has a photo. The instance variable is added to the model like this:

 def delete_photo=(value)
    @delete_photo = !value.to_i.zero?
  end
  
  def delete_photo
    !!@delete_photo
  end
  alias_method :delete_photo?, :delete_photo

 

before_validation :clear_photo

# Later in the model
def clear_photo
  self.photo = nil if delete_photo? && !photo.dirty?
end

 

def update
  if @user.update_attributes(params[:user])
    flash_and_redirect_to('User profile was saved successfully.', :notice, users_path(@user))
  else
    page_title.unshift('Edit user')
    render(:action => 'edit')
  end
end

 

When I was trawling the interwebs to see if anybody else had some code to do this I didn’t find anything, so please let me know if you’ve come up with a better idea but haven’t yet had chance to share it with the world!

Getting clever with validations

I’ve added this section thanks to DMitry’s comment.

Paperclip allows you to validate the presence, content type and size of an attachment file using the validates_attachment_presence, validates_attachment_content_type and validates_attachment_size methods.

But what if you want to do something more advanced? For example let’s say we have a Track model that represents uploaded MP3 files and, because we want to preserve the musical integrity of our site, we want to prevent files from certain ‘artists’ being uploaded. To do this we can use a custom validation method:

class Track < ActiveRecord::Base

  has_attached_file :mp3

  validates_attachment_presence :mp3
  validates_attachment_content_type :mp3, :content_type => [ 'application/mp3', 'application/x-mp3', 'audio/mpeg', 'audio/mp3' ]
  validates_attachment_size :mp3, :less_than => 10.megabytes

  validate :must_have_valid_artist_tag

  protected

    def must_have_valid_artist_tag
      Mp3Info.open(mp3.to_file.path) do |mp3info|
        errors.add(:mp3, 'must not be a Michael Bolton song (what are you thinking?!)') if mp3info.tag.artist == 'Michael Bolton'
      end if mp3?
    rescue Mp3InfoError => e
      errors.add(:mp3, "unable to process file (#{e.message})")
    end

end

 

This model makes use of the gem to access the ID3 tags: you’ll need to install it and set up the necessary config.gem line in your environment.rb file to get this example working.

The first four lines of the model are straight calls to Paperclip methods: they setup the attachment and ensure it is validated for presence, content type and size. The model then contains a validate callback for the must_have_valid_artist_tag method: this is where the good stuff happens.

Here’s a line-by-line breakdown:

  1. If a new MP3 file has been attached then at the time of validation it won’t have been written to the correct location on the server (or S3 bucket). Fortunately the to_file method means we don’t have to worry about this: it returns a File object that will either refer to an existing attachment file or the new, temporary, uploaded file. The first line of the validation method passes the path name of this file to the Mp3Info class so that it can process it.

  2. In this simple example the validation checks if the artist tag of the MP3 file is set to a particular artist and flags an error as appropriate.

  3. Before doing any of the above it’s a good idea to check that a file was actually attached: Paperclip provides a simple way to do this by calling the mp3? method which returns true if a file has been attached. The name of this method is based on the name of your attachment, so for example if your model contains has_attached_file :photo then the photo? method will be used check for an attached file.

  4. The Mp3Info class will raise an Mp3InfoException if something goes wrong. We need to rescue it in case an invalid MP3 file is uploaded.

  5. To keep this example simple, if an exception occurs an error is added to the mp3 attribute containing the exception message: you could naturally do something more impressive here.

By providing you with direct access to the attachment file using the to_file method, Paperclip enables you to do pretty much anything with the attachment, either in a validation like the one shown above or in a different model callback such as before_save.

分享到:
评论

相关推荐

    ruby插件.rar

    对于文件操作,`paperclip` 和 `carrierwave` 是常见的文件上传插件,它们方便地处理图片和其他文件的上传和存储。另外,`active_storage` 是 Rails 5.2 引入的内置文件处理系统,与 AWS S3 或其他云存储服务集成,...

    rails 多图上传.txt

    在实现Rails应用中的多图上传功能时,通常需要借助于特定的插件或Gem来简化开发流程并增强功能。以下两个工具是必不可少的: 1. **Paperclip(Gem)** - **用途**:用于后台文件处理,是一款非常强大的工具,支持...

    ruby on rail.pdf

    例如,Devise用于用户认证,CanCanCan处理权限控制,Paperclip或Carrierwave处理文件上传,而Rspec和Capybara则提供了强大的测试工具。 总的来说,Ruby on Rails以其高效的开发流程、优雅的语法和强大的社区支持,...

    photo_journal:一个允许用户创建自己的照片日记时间流逝的网络应用程序

    2. 图片上传:可能使用Paperclip或Carrierwave这样的gem处理图片上传,可以处理图片的缩放、格式转换等问题。 3. 时间线展示:通过ActiveRecord查询用户的照片,并按照时间顺序显示,形成时间流逝的效果。 4. 数据...

    awesome-rails-gem-zh_CN, Rails 常用 Gem 列表 - Awesome Rails Gem 中文版.zip

    4. **Paperclip** 和 **CarrierWave**:这两个Gem用于文件上传,支持图片处理和存储服务集成。 5. **Pundit**:轻量级的授权库,用于创建更细粒度的权限控制,相比CanCanCan更简单。 6. **Bootstrap-Sass** 和 **...

    3DGallery:连接到Web服务并在MySQL中存储用户图库的Rails应用程序。 WebGL还与Three.js一起成为其荣耀所在

    Rails的Devise gem常用于用户身份验证,而文件上传通常可以通过Paperclip或Carrierwave等gem来实现。这些gem允许用户上传3D模型文件,并将它们的元数据存储在MySQL数据库中。 **Web服务连接** 3DGallery可能与其他...

    muse-my-vinyls

    “muse-my-vinyls”很可能还使用了其他常见的Rails插件和库,例如Devise用于用户认证,Paperclip或Carrierwave用于文件上传(如唱片封面图片),以及 Acts As Taggable On 用于标签系统,让用户可以按标签查找和分类...

    blog

    Ruby on Rails还提供了许多优秀的gem(Ruby的库或插件),如Pundit或CanCanCan用于授权,Paperclip或Carrierwave处理文件上传(如文章的封面图片),以及Ransack进行高级搜索。这些gem大大简化了开发过程。 此外,...

    Chatter:一个用ruby构建的社交网络

    Chatter项目可能还使用了一些常见的Rails插件,如Devise(用户认证),Paperclip或Carrierwave(文件上传),或者ActiveAdmin(后台管理)。此外,它可能有自己的用户系统、消息传递功能、关注/好友系统以及动态流等...

    fridge-overflow:问答论坛,满足您所有的美食需求

    8. **社区和插件**:Ruby拥有丰富的生态系统,包括许多社区维护的gem,如Bootstrap用于前端美化,Pundit或CanCanCan实现授权管理,Paperclip或Carrierwave处理上传的图片等。 9. **响应式设计**:为了适应不同设备...

    contre_pied_prod

    此外,Rails还依赖于许多 Gems(Ruby的包管理系统)来提供额外的功能,如Devise用于用户认证,Bootstrap或Foundation用于前端框架,Paperclip或Carrierwave处理文件上传等。这些Gems通常在`Gemfile`中列出,并通过`...

Global site tag (gtag.js) - Google Analytics