Gem Paperclip: Uploading files and pictures into your Rails application

Hello everybody! Here I am again to talk a bit more about Ruby on Rails. And today I’m going to show you a very simple way to upload your attachments or a picture.

3

It’s a gem called paperclip, you can find it here!

There’s a quick README file teaching you how to use it, so I will not totally focus on it, I’ll just create a new project, and show you as an example! It’s really cool and pretty easy.

Ok, so let’s starting by the requirements. The first thing you’re going to need is the ImageMagick to make it work correctly. I’m using Ubuntu 10.10, this is the easiest way to install, go to your terminal and:

1 $ sudo apt-get update 2 $ sudo apt-get install imagemagick

That’s it!

Ok, so let’s jump into Rails world!

Create a new project, and opening your favorite editor.

1 $ rails new newapp 2 $ cd /newapp 3 $ gmate .

As far as it’s just a test, let’s use scaffold to create a simple module where we can add our paperclip work.

1 $ rails g scaffold user name:string email:string

Ok, everything already set up.

Before start using paperclip, we need to add it in our Gemfile.

1 gem "paperclip", "~> 2.3"

I’ll give you two examples, first one using paperclip to add an attachments and later a picture. It’s pretty much the same thing, but two examples are better than just one.

So, let’s create our migration first.

1 $ rails g migration add_attach_paperclip 2 $ rails g migration add_pic_paperclip

Alright, both migrations created. It’s time to start coding!

Open up both migrations, and follow the code below.

1 class AddattachPaperclip < ActiveRecord::Migration 2 def self.up 3 add_column :users, :attach_file_name, :string 4 add_column :users, :attach_content_type, :string 5 add_column :users, :attach_file_size, :integer 6 add_column :users, :attach_updated_at, :datetime 7 end 8 9 def self.down 10 remove_column :users, :attach_file_name 11 remove_column :users, :attach_content_type 12 remove_column :users, :attach_file_size 13 remove_column :users, :attach_updated_at 14 end 15 end

1 class AddPicPaperclip < ActiveRecord::Migration 2 def self.up 3 add_column :users, :pic_file_name, :string 4 add_column :users, :pic_content_type, :string 5 add_column :users, :pic_file_size, :integer 6 add_column :users, :pic_updated_at, :datetime 7 end 8 9 def self.down 10 remove_column :users, :pic_file_name 11 remove_column :users, :pic_content_type 12 remove_column :users, :pic_file_size 13 remove_column :users, :pic_updated_at 14 end 15 end

Alright, time to run our migrations.

1 $ rake db:migrate

So, open your model and check out the code below

1 class User < ActiveRecord::Base 2 validates :name, :presence => true 3 validates :email, :presence => true 4 has_attached_file :pic, :styles => 5 { :medium => "300x300>", :thumb => "100x100>" } 6 has_attached_file :attach 7 end

There’s no need to change our controller since scaffold did all that word for us.

Well, as you can see, scaffold used partials, so you just need to change the _form.html.erb file to modify new and edit views. Open that up.

Pay attention that the form_for must be multipart.

1 # First line should be 2 <% form_for @user, :html => { :multipart => true } 3 do |f| %> 4 5 # Then, add the file_field fields. 6 <p> 7 <b> attachment </b><br/> 8 <%= f.file_field :attach %> 9 </p> 10 11 <p> 12 <b> Picture </b><br/> 13 <%= f.file_field :pic %> 14 </p>

Ok, just one last step to get it done. We have set up everything, but there’s not show yet.

So, open that up and chose the one that fits you better.

1 # FOR THE ATTACHMENT 2 <a href="<%= @user.attach.url %> "> 3 <b> File attached </b></a> 4 <br/> 5 # FOR THE PICTURES 6 # Will show the real size picture 7 <%= image_tag @user.pic.url %> 8 <br/> 9 # Will the style MEDIUM configured before 10 # in your model 11 <%= image_tag @user.pic.url(:medium) %> 12 <br/> 13 # Will the style THUMB configured before 14 # in your model 15 <%= image_tag @user.pic.url(:thumb) %> 16 <br/>

12

And there you go! Everything working perfectly!

Pretty cool, huh? It’s safe, easy and important!

Do not forget to read the documentation of paperclip. It’s important.

So, that’s it for today. Hope you have enjoyed.

I’ll unleash this project here, just created a github repository, if you feel more confortable reading my code instead of following the tutorial, here it is!

Thanks for the attention! Feel free to share this tutorial and if you have any doubts or want to add something, please use the comment area below!

4

About these ads

49 comments

  1. That’s an old cartoon in the picture attachment… Today, it’s more like this:

    (1..100).each {|i| puts ‘i will not throw spit balls in class’}

  2. no puedo hacer que funcione! me sale un error al subir cualquier producto y me marca este error:

    Producto model missing required attr_accessor for ‘imagen_file_name’

    alguna sugerencia O.o!

      1. Sorry again that took so long to answer you, been busy.
        Can you please recheck your migrations? Are you sure that you created them with the correct name? I guess it can solve your problem.

        Regards.

  3. Thanks for your article

    I did the same what you mentioned above but i am getting error like

    “User model missing required attr_accessor for ‘attach_file_name'”

    what should i do now ….?

    1. Hello…

      You aren’t the first person telling me that.. weird, since I tested here before.
      So, can you please recheck your migrations, to see if there’s anything mistyped. And second, have you run the command rake db:migrate?
      Are you sure your migrations were correctly migrated? Hope it helps.

      PS. I think it should be a problem with migrations/database.

      Regards.

      1. i created a project in that i gave a option to upload image. But in the edit page i can’t able to update the image.
        the code in the model is:

        class Uploadimage < ActiveRecord::Base

        def image_file=(input_data)
        self.filename = input_data.original_filename
        self.content_type = input_data.content_type.chomp
        self.data = input_data.read
        end
        end

        code in the controller is:

        class UploadimagesController @uploadimages }
        end
        end

        # GET /uploadimages/1
        # GET /uploadimages/1.xml
        def show
        @uploadimage = Uploadimage.find(params[:id])

        respond_to do |format|
        format.html # show.html.erb
        format.xml { render :xml => @uploadimage }
        end
        end

        # GET /uploadimages/new
        # GET /uploadimages/new.xml
        def new
        @uploadimage = Uploadimage.new

        respond_to do |format|
        format.html # new.html.erb
        format.xml { render :xml => @uploadimage }
        end
        end

        # GET /uploadimages/1/edit
        def edit
        @uploadimage = Uploadimage.find(params[:id])
        end

        # POST /uploadimages
        # POST /uploadimages.xml
        def create
        @uploadimage = Uploadimage.new(params[:uploadimage])

        respond_to do |format|
        if @uploadimage.save
        format.html { redirect_to(@uploadimage, :notice => ‘Uploadimage was successfully created.’) }
        format.xml { render :xml => @uploadimage, :status => :created, :location => @uploadimage }
        else
        format.html { render :action => “new” }
        format.xml { render :xml => @uploadimage.errors, :status => :unprocessable_entity }
        end
        end
        end

        # PUT /uploadimages/1
        # PUT /uploadimages/1.xml
        def update
        @uploadimage = Uploadimage.find(params[:id])

        respond_to do |format|
        if @uploadimage.update_attributes(params[:uploadimage])
        format.html { redirect_to(@uploadimage, :notice => ‘Uploadimage was successfully updated.’) }
        format.xml { head :ok }
        else
        format.html { render :action => “edit” }
        format.xml { render :xml => @uploadimage.errors, :status => :unprocessable_entity }
        end
        end
        end

        def code_image
        @image_data = Uploadimage.find(params[:id])
        @image = @image_data.data
        send_data (@image, :type => @image_data.content_type,
        :filename => @image_data.filename,
        :disposition => ‘inline’)
        end

        # DELETE /uploadimages/1
        # DELETE /uploadimages/1.xml
        def destroy
        @uploadimage = Uploadimage.find(params[:id])
        @uploadimage.destroy

        respond_to do |format|
        format.html { redirect_to(uploadimages_url) }
        format.xml { head :ok }
        end
        end
        end

      2. Hello, I’m so sorry that took so long to answer you, I’ve been busy and no time to work with rails.
        Well, I’m far from being an expert in ror, but I guess you cannot update the file, what you can do is:
        – Show to the user the current file (like the index page)
        – Then let the user replace it for a new file.

        PS. When I say file, it works for pictures too.
        Was I helpful?

        Regards,
        Felipe

  4. Thanks by explain and share your knowledge. I searched in various blogs, but them explain upload using only images, with no files.

  5. Hi! I have an existing table consisting of columns ‘title’ and ‘data’. What should I do if I want to add another column that will have a pdf attachment?

    1. Hello,

      If you’d like to add another column you must create another migration like this (where user is your table)

      class AddattachPaperclip < ActiveRecord::Migration
      def self.up
      add_column :users, :attach_file_name, :string
      add_column :users, :attach_content_type, :string
      add_column :users, :attach_file_size, :integer
      add_column :users, :attach_updated_at, :datetime
      end

      def self.down
      remove_column :users, :attach_file_name
      remove_column :users, :attach_content_type
      remove_column :users, :attach_file_size
      remove_column :users, :attach_updated_at
      end
      end

      Then you also have to config your model with one more line (where attach is your column previously created)
      has_attached_file :attach

      Then just follow the rest of the tutorial to config your viewer, if you have any problem with that let me know and i’ll try to help you :)
      Good luck!

      Regards,
      Felipe

  6. HOW TO UP A LOAD FILE WITH OUT ANY GEMS/PLUGIN IN RAILS 3………..

    FILE UPLOAD RIDING ME CRAZY ……..HELP ME PLZ

  7. “$ rake db:migrate
    == CreateUsers: migrating ====================================================
    — create_table(:users)
    -> 0.0020s
    == CreateUsers: migrated (0.0020s) ===========================================

    rake aborted!
    An error has occurred, this and all later migrations canceled:

    uninitialized constant AddAttachPaperclip”

    any solution

    1. Hello Sohail,

      Can you please tell me which version of Ruby and Rails are you using?

      You could try to use a latter version of paper clip like:
      gem ‘paperclip’, :git => “git://github.com/thoughtbot/paperclip.git”

      don’t forget to run bundle:install :)

      Tell me if you still have problems with it.
      Regards,
      Felipe

  8. while opening the root page(new.html.erb) getting error :

    Routing Error

    undefined method `has_attached_file’ for #

    Try running rake routes for more information on available routes.

  9. hello every body.I did same as code you gave me but not run.I am using Window.I’m afraid this is reason not run.Could you help me

  10. I try to run the rake db:migrate but I get this error

    An error has occurred, this and all later migrations canceled:

    uninitialized constant AddAttachPaperclip
    /usr/local/rvm/gems/ruby-1.9.3-p392/gems/activesupport-3.2.12/lib/active_support/inflector/methods.rb:230:in `block in constantize’

  11. hi
    /home/encore/.rvm/gems/ruby-1.9.3-p374@global/gems/bundler-1.2.3/lib/bundler.rb:263: warning: Insecure world writable dir /usr/local/sbin in PATH, mode 040777
    rake aborted!
    An error has occurred, this and all later migrations canceled:

    uninitialized constant AddAttachPaperclip/home/encore/.rvm/gems/ruby-1.9.3-p374/gems/activesupport-3.2.13/lib/active_support/inflector/methods.rb:230:in `block in constantize’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/activesupport-3.2.13/lib/active_support/inflector/methods.rb:229:in `each’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/activesupport-3.2.13/lib/active_support/inflector/methods.rb:229:in `constantize’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/activesupport-3.2.13/lib/active_support/core_ext/string/inflections.rb:54:in `constantize’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/activerecord-3.2.13/lib/active_record/migration.rb:538:in `load_migration’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/activerecord-3.2.13/lib/active_record/migration.rb:533:in `migration’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/activerecord-3.2.13/lib/active_record/migration.rb:528:in `migrate’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/activerecord-3.2.13/lib/active_record/migration.rb:720:in `block (2 levels) in migrate’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/activerecord-3.2.13/lib/active_record/migration.rb:775:in `call’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/activerecord-3.2.13/lib/active_record/migration.rb:775:in `block in ddl_transaction’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/activerecord-3.2.13/lib/active_record/connection_adapters/abstract/database_statements.rb:192:in `transaction’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/activerecord-3.2.13/lib/active_record/transactions.rb:208:in `transaction’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/activerecord-3.2.13/lib/active_record/migration.rb:775:in `ddl_transaction’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/activerecord-3.2.13/lib/active_record/migration.rb:719:in `block in migrate’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/activerecord-3.2.13/lib/active_record/migration.rb:700:in `each’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/activerecord-3.2.13/lib/active_record/migration.rb:700:in `migrate’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/activerecord-3.2.13/lib/active_record/migration.rb:570:in `up’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/activerecord-3.2.13/lib/active_record/migration.rb:551:in `migrate’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/activerecord-3.2.13/lib/active_record/railties/databases.rake:193:in `block (2 levels) in ‘
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/rake-10.0.4/lib/rake/task.rb:246:in `call’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/rake-10.0.4/lib/rake/task.rb:246:in `block in execute’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/rake-10.0.4/lib/rake/task.rb:241:in `each’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/rake-10.0.4/lib/rake/task.rb:241:in `execute’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/rake-10.0.4/lib/rake/task.rb:184:in `block in invoke_with_call_chain’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/rake-10.0.4/lib/rake/task.rb:177:in `invoke_with_call_chain’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/rake-10.0.4/lib/rake/task.rb:170:in `invoke’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/rake-10.0.4/lib/rake/application.rb:143:in `invoke_task’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/rake-10.0.4/lib/rake/application.rb:101:in `block (2 levels) in top_level’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/rake-10.0.4/lib/rake/application.rb:101:in `each’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/rake-10.0.4/lib/rake/application.rb:101:in `block in top_level’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/rake-10.0.4/lib/rake/application.rb:110:in `run_with_threads’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/rake-10.0.4/lib/rake/application.rb:95:in `top_level’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/rake-10.0.4/lib/rake/application.rb:73:in `block in run’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/rake-10.0.4/lib/rake/application.rb:160:in `standard_exception_handling’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/gems/rake-10.0.4/lib/rake/application.rb:70:in `run’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/bin/ruby_noexec_wrapper:14:in `eval’
    /home/encore/.rvm/gems/ruby-1.9.3-p374/bin/ruby_noexec_wrapper:14:in `’
    Tasks: TOP => db:migrate
    (See full trace by running task with –trace)

  12. HI,

    I am completed paperclip functionality but finally getting error pls hel me

    ActiveModel::MassAssignmentSecurity::Error in UserDetailsController#create

    Can’t mass-assign protected attributes: attach, pic

  13. Hi, So after i edited user.rb model I got this error when i run it

    undefined method `has_attached_file’ for #

    Thanks for your help

  14. Yea, I’m sorry but i’m very new in Ruby. Is it just Ctrl + c and start the server again using command $ rails server ?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s