205 Basic file uploads and image versions [2d]

Updated . Posted . Visible to the public.

Goals

  • Learn to treat files as an ActiveRecord attribute type, like :string or :integer

Research

Exercise

In MovieDB, allow movie authors to upload a movie poster using the carrierwave gem:

  • The poster should be uploaded in the form where we can also fill in title, year, etc.
  • On the movie show view, render a poster version that is 400 pixel wide, with a height that respects the aspect ratio of the original image
  • On the movie index view, render a poster version that is 100 pixel wide and cropped to 100 pixel height, regardless of the original aspect ratio. The image should be cropped to the square aspect ratio, not distorted.
  • On the movie show view, offer a link to download the original poster image file.
  • The download link should always download the image and never display it inline within the browser window. You can do so with either the [download] HTML attribute, or by sending a Content-Disposition header when delivering the image.
  • When editing a movie, offer controls to delete or replace the poster image file.
  • There should be a validation allowing only uploads of .jpg, .jpeg, .png and .webp files.
  • You do not need to treat movie posters as confidential, so it's not important if an unauthorized user can see a poster.
  • When saving a poster and there is a validation error on another field (e.g. missing title), the file selection should be preserved when the form is displayed again. Use the CarrierWave cache Show archive.org snapshot for this.

Make sure to add tests for adding, changing and deleting a poster image:

  • An integration test for the happy path
    • User uploads image, sees an image review, downloads image.
    • Capybara needs the browser to show an interactive HTML page to be happy. Capybara methods will fail when the browser shows a "Save as" dialog or when it displays an inline download within the browser window. See Testing File Downloads with Selenium for alternatives.
  • Unit tests for details
    • Rendering of image versions and validation of file extension can be tested with RSpec
    • These can be model specs for either the Movie or your PosterUploader
    • To save a poster, just assign any IO object to the Movie#poster= setter and save the movie.
    • In a real HTTP request scenario, the assigned IO object also carries information about image's original filename and its MIME type. You can build a similar IO object like this:
      movie.poster = Rack::Test::UploadedFile.new('spec/fixtures/poster.jpg', 'image/jpeg')
      
Henning Koch
Last edit
Paul Demel
License
Source code in this card is licensed under the MIT License.
Posted by Henning Koch to makandra Curriculum (2015-07-08 17:43)