Date published: 11-25-2013
Rails version: 4.0.0
File upload
Web sites are a very visual form of communication, and so it’s not that uncommon for users to want to add photographs to their sites. Most sites let you load an avatar for your user page, and some sites like flickr and Photobucket are based around hosting images. In this tutorial, we’re going to use a gem called Carrierwave upload photos and display them on a web page.
Copy the template site
The first thing we need to do is copy our template site and create a new project from it. Open a terminal window and switch to the directory where the template Bootstrap site is located. Run the following commands:
$ cp -r template_bootstrap_site/ photo_upload $ cd photo_upload/
It’s a good idea now to change the module name just like we did in this tutorial in the section titled, “Update the module information.” Make sure to commit your changes to Git before moving on.
Add the Carrierwave gem
Open the Gemfile and add the following line:
gem 'carrierwave', '0.9.0' gem 'mini_magick', '3.6.0'
We need to run a few commands in the console to create the files we need. We need to install Imagemagick to support resizing of images, and I’m using a Mac with Homebrew. If you’re on a different setup, you’ll need to manually install Imagemagick and ignore the first command. Switch to the console and run these commands:
$ brew install imagemagick $ bundle install $ rails generate uploader Photo create app/uploaders/photo_uploader.rb
If you open the uploader that was created, you should see a few commands along with a lot of comments. Notice that a method has been defined called store_dir. We can change this to specify where we want uploaded photos to be saved on the server. We’ll leave it as it is, but we need to make one change to make sure uploaded photos don’t get committed to Git. Open the .gitignore file and add the following line at the bottom:
uploads/
This will make sure that any files that are uploaded won’t get saved when we commit to Git. We need to make some changes to the photo_uploader.rb file to accommodate what we want to do with our photos, but first we need to define what our requirements are. We only want users to be able to upload photo files, which we can do by uncommenting the extension_white_list method that’s already provided. We’re going to show a gallery page of all photos that have been uploaded and a page that shows individual photos when we click on one in the gallery. Add the following to app/uploaders/photo_uploader.rb:
process :resize_to_fit => [800, 800] version :thumb do process :resize_to_fill => [200,200] end def extension_white_list %w(jpg jpeg gif png) end
The call to process will be called on the photo that is uploaded ensuring that the photo we save is resized so that the longest side is a maximum of 800 pixels. This will keep it from saving huge files because we know we only want to display that maximum size of photo on our pages. The call to version tells Carrierwave that we want a version of the photo called thumb that is resized to be 200 x 200 pixels. We’ll use that thumb on our gallery page.
Create the photo model and views
The next thing we need to do is create a model to hold the photos. Switch to the console and run the following commands:
$ rails g model photo photo_file:string invoke active_record create db/migrate/20131125182817_create_photos.rb create app/models/photo.rb $ rake db:migrate == CreatePhotos: migrating =================================================== -- create_table(:photos) -> 0.0024s == CreatePhotos: migrated (0.0030s) ========================================== $ annotate Annotated (1): Photo
The new file is basically an empty model. We need to tell Rails we want the photo file to be uploaded using the photo_uploader we just made. Add this line to app/models/photo.rb:
mount_uploader :photo_file, PhotoUploader
That’s all we have to do in our model, so let’s shift our attention to the views. The first thing we should do is add a call in config/routes.rb for our photo controller:
resources :photos, only: [:new, :create, :show]
Next we need to create our controller and define the actions to add new and show our photos. Create a new file call app/controllers/photos_controller.rb:
class PhotosController < ApplicationController def new @photo = Photo.new end def create @photo = Photo.new(photo_params) if @photo.save redirect_to root_path else render 'new' end end def show @photo = Photo.find(params[:id]) end private def photo_params params.require(:photo).permit(:photo_file) end end
While we’re modifying controllers, let’s make a change to app/controllers/static_pages_controller.rb to get all photos:
class StaticPagesController < ApplicationController def home @photos = Photo.all end def about end end
Now we need to create new views for pages to upload photos and view the photos that have been uploaded. Let’s update our header so we have a convenient link to the page to upload a photo. Open app/views/layouts/_header.html.erb and make these changes:
<%= link_to "Photos", root_path, class: "brand" %> <div class="nav-collapse collapse"> <ul class="nav"> <li><%= link_to "New photo", new_photo_path %></li> </ul>
Let’s also update our home page to show a gallery of all the photos that have been uploaded. Change app/views/static_pages/home.html.erb to look like this:
<% provide(:title, "Home Page") %> <div class="row"> <p>There are <%= @photos.count %> photos.</p> <% @photos.each do |photo| %> <%= link_to image_tag(photo.photo_file.thumb.url), photo %> <% end %> </div>
Next let’s make the page to upload new photos. Create a file called app/views/photos/new.html.erb and fill it in with this:
<% provide(:title, "New Photo") %> <h1>New Photo</h1> <%= form_for @photo, :html => {:multipart => true} do |f| %> <p> <label>Photo</label> <%= f.file_field :photo_file %> <%= f.hidden_field :photo_file_cache %> </p> <p> <%= f.submit %> </p> <% end %>
We still need a page to show the images when the user clicks on a photo in the gallery. Create a new file at app/views/photos/show.html.erb and fill it in with this:
<% provide(:title, "Show Photo") %> <center> <%= image_tag @photo.photo_file.url %> </center>
That’s all we need to do to get it working. Restart the Rails server and try out adding new photos. They should show up in the gallery on our home page, and if you click an individual photo, it should redirect you to the page to view the bigger photo. Since we’re done, let’s commit our changes in Git so we don’t lose them:
$ git add . $ git commit -m "Added photo uploading"
The source code for this tutorial can be found on Github at: