Rails Carrierwave Uploading to Aws but Not Displaying
Read Time: xi mins Languages:
This is another article in the "Uploading with Track" serial. Today we are going to meet Carrierwave—1 of the virtually popular file uploading solutions for Rail. I like Carrierwave because information technology is easy to get started, it has lots of features out of the box, and it provides dozens of "how to" articles written by the members of the community, so you lot won't go lost.
In this article, you will learn how to:
- Integrate Carrierwave into your Rails app
- Add validations
- Persist files across requests
- Remove files
- Generate thumbnails
- Upload files from remote locations
- Introduce multiple file uploads
- Add support for cloud storage
The source code for this commodity is available on GitHub. Bask reading!
Laying the Foundations
As always, start by creating a new Rails application:
rails new UploadingWithCarrierwave -T
For this demo I'll be using Rails five.0.two. Please note that Carrierwave 1 supports only Rails four+ and Ruby 2. If yous are notwithstanding riding on Rails 3, so hook up Carrierwave version 0.11.
To see Carrierwave in action, nosotros are going to create a very simple blogging awarding with a sole Post
model. It will have the following main attributes:
-
title
(cord
) -
body
(text
) -
image
(string
)—this field is going to contain an paradigm (a file's proper name, to exist precise) attached to the post
Generate and utilise a new migration:
runway g model Post championship:cord body:text paradigm:string runway db:migrate
Gear up some routes:
config/routes.rb
resources :posts root to: 'posts#alphabetize'
Too, create a very basic controller:
posts_controller.rb
class PostsController < ApplicationController before_action :set_post, only: [:evidence, :edit, :update] def index @posts = Post.order('created_at DESC') cease def show end def new @post = Post.new end def create @post = Post.new(post_params) if @post.save redirect_to posts_path else render :new end end def edit stop def update if @postal service.update_attributes(post_params) redirect_to post_path(@mail service) else render :edit end end private def post_params params.require(:post).permit(:championship, :torso, :paradigm) finish def set_post @post = Post.notice(params[:id]) end end
Now let's arts and crafts the index view:
views/posts/index.html.erb
<h1>Posts</h1> <%= link_to 'Add together mail', new_post_path %> <%= render @posts %>
And the respective partial:
views/posts/_post.html.erb
<h2><%= link_to mail service.title, post_path(postal service) %></h2> <p><%= truncate(post.body, length: 150) %></p> <p><%= link_to 'Edit', edit_post_path(post) %></p> <hr>
Here I am using the Railtruncate
method to brandish but the showtime 150 symbols from the mail. Earlier nosotros create other views and a form fractional, let's firstly integrate Carrierwave into the application.
Integrating Carrierwave
Drib in a new gem into the Gemfile:
Gemfile
gem 'carrierwave', '~> 1.0'
Run:
bundle install
Carrierwave stores its configuration insideuploadersthat are included into your models. To generate an uploader, use the post-obit control:
rails generate uploader Image
Now, within app/uploaders, you lot will find a new file called image_uploader.rb. Annotation that information technology has some useful comments and examples, so you may use it to get started. In this demo nosotros volition use ActiveRecord, but Carrierwave as well has back up for Mongoid, Sequel, and DataMapper.
Adjacent, we need to include or mount this uploader into the model:
models/post.rb
mount_uploader :image, ImageUploader
The uploader already has sane default settings, but at the very least nosotros demand to choose where the uploaded files will be stored. For now, permit's utilize file storage:
uploaders/image_uploader.rb
storage :file
By default, files will be placed inside the public/uploads directory, so it is best to exclude it from the version control organisation:
.gitignore
public/uploads
You may as well modify thestore_dir
method inside your uploader to cull some other location.
At this point, we tin can create a new view and a class fractional to start uploading files:
views/posts/new.html.erb
<h1>Add post</h1> <%= render 'course', post: @post %>
views/posts/_form.html.erb
<%= form_for post practice |f| %> <div> <%= f.characterization :title %> <%= f.text_field :championship %> </div> <div> <%= f.label :body %> <%= f.text_area :body %> </div> <div> <%= f.label :image %> <%= f.file_field :paradigm %> </div> <%= f.submit %> <% end %>
Note that the PostsController
does non need to be modified as nosotros already permitted the epitome
attribute.
Lastly, create the edit view:
views/posts/edit.html.erb
<h1>Edit mail</h1> <%= return 'form', mail: @post %>
That's information technology! You may kick the server and try to create a mail with an image. The problem is that this image is not visible anywhere, so let'due south proceed to the side by side section and add a show page!
Displaying Images
Then, the just view nosotros take non created nonetheless is show. Add it now:
views/posts/show.html.erb
<%= link_to 'All posts', posts_path %> <h1><%= @mail service.title %></h1> <%= image_tag(@post.image.url, alt: 'Image') if @post.paradigm? %> <p><%= @mail.body %></p> <p><%= link_to 'Edit', edit_post_path(@post) %></p>
As you tin can encounter, displaying an attachment is really easy: all you need to exercise is say @postal service.prototype.url
to catch an paradigm'south URL. To get a path to the file, use thecurrent_path
method. Annotation that Carrierwave likewise provides an image?
method for us to check whether an attachment is present at all (the prototype
method itself will never return nil
, even if the file is not present).
Now, after navigating to a post, you should see an epitome, but information technology might appear likewise big: later all, we are not restricting dimensions anywhere. Of course, we could have scaled the image down with some CSS rules, just it is much improve to generate a thumbnail after the file has been uploaded. This, notwithstanding, requires some additional steps.
Generating Thumbnails
In order to crop and calibration images, we need a separate tool. Out of the box Carrierwave has back up for RMagick and MiniMagick gems that, in plough, are used to manipulate images with the help of ImageMagick. ImageMagick is an open-source solution assuasive you to edit existing images and generate new ones, so before proceeding you need to download and install it. Adjacent, you lot are complimentary to pick either of the two gems. I'll stick with MiniMagick, because it is much easier to install and it has ameliorate support:
Gemfile
precious stone 'mini_magick'
Run:
package install
Then include MiniMagick into your uploader:
uploaders/image_uploader.rb
include CarrierWave::MiniMagick
Now we simply need to introduce a new version to our uploader. The concept of versions (or styles) is used in many file uploading libraries; it simply means that additional files based on the original attachment volition be created with, for instance, different dimensions or formats. Introduce a new version chosen thumb
:
uploaders/image_uploader.rb
version :pollex do process resize_to_fill: [350, 350] end
Yous may have equally many versions as you like and, what's more, versions can fifty-fifty exist built on tiptop of other ones:
uploaders/image_uploader.rb
version :small_thumb, from_version: :thumb do procedure resize_to_fill: [twenty, 20] cease
If you have already uploaded some images, they won't have thumbnails available. This is not a problem, though, equally you can re-create them from the Rails console:
rail c Postal service.find_each {|mail| post.image.recreate_versions!(:thumb) if mail.paradigm?}
Lastly, display your thumbnail with a link to the original epitome:
views/posts/show.html.erb
<%= link_to(image_tag(@post.epitome.thumb.url, alt: 'Image'), @post.image.url, target: '_blank') if @post.image? %>
Boot the server and discover the result!
Calculation Validations
Currently our uploading works, but we're non validating user input at all, which is, of grade, bad. As long every bit we want to piece of work only with images, let's whitelist .png, .jpg and .gif extensions:
uploaders/image_uploader.rb
def extension_whitelist %w(jpg jpeg gif png) end
You lot may also add content blazon checks by defining a content_type_whitelist
method:
uploaders/image_uploader.rb
def content_type_whitelist /paradigm\// end
Alternatively, it is possible to blacklist some file types, for example executables, past defining thecontent_type_blacklist
method.
Autonomously from checking a file'southward type and extension, let'south enforce it to be less than i megabyte. To practise it, we'll require an boosted gem supporting file validations for ActiveModel:
Gemfile
precious stone 'file_validators'
Install it:
package install
Now introduce the desired validations (note that I am also adding checks for the title
and body
attributes):
models/post.rb
validates :title, presence: truthful, length: {minimum: two} validates :body, presence: truthful validates :image, file_size: { less_than: ane.megabytes }
The next thing to do is to add I18n translations for Carrierwave's error messages:
config/locales/en.yml
en: errors: letters: carrierwave_processing_error: "Cannot resize paradigm." carrierwave_integrity_error: "Not an epitome." carrierwave_download_error: "Couldn't download image." extension_whitelist_error: "You are not allowed to upload %{extension} files, allowed types: %{allowed_types}" extension_blacklist_error: "You are not allowed to upload %{extension} files, prohibited types: %{prohibited_types}"
Currently, we do not display validation errors anywhere, and then let'due south create a shared partial:
views/shared/_errors.html.erb
<% if object.errors.any? %> <h3>Some errors were constitute:</h3> <ul> <% object.errors.full_messages.each do |message| %> <li><%= message %></li> <% end %> </ul> <% end %>
Utilize this fractional inside the form:
views/posts/_form.html.erb
<%= return 'shared/errors', object: mail %>
Now endeavour to upload some invalid files and observe the result. It should work, but if you cull a valid file and practice not fill in the championship or trunk, and then the checks will notwithstanding neglect and an mistake will be displayed. Notwithstanding, the file field will be cleared out and the user will need to choose the prototype again, which is not very user-friendly. To fix it, nosotros demand to add another field to the form.
Persisting Files Across Requests
Persisting files across form redisplays is actually quite easy. All you lot need to do is add together a new subconscious field and allow information technology inside the controller:
views/shared/_form.html.erb
<%= f.label :paradigm %> <%= f.file_field :image %><br> <%= f.hidden_field :image_cache %>
posts_controller.rb
params.require(:postal service).permit(:championship, :body, :paradigm, :image_cache)
Now the image_cache
volition be populated automatically and the image won't exist lost. It may be helpful to display a thumbnail as well so that user understands the image was processed successfully:
views/shared/_form.html.erb
<% if post.image? %> <%= image_tag post.epitome.thumb.url %> <% stop %>
Removing Images
Another very common feature is the ability to remove fastened files when editing a tape. With Carrierwave, implementing this feature is not a problem. Add a new checkbox to the form:
views/shared/_form.html.erb
<% if post.image? %> <%= image_tag post.image.thumb.url %> <div> <%= label_tag :remove_image do %> Remove image <%= f.check_box :remove_image %> <% end %> </div> <% end %>
And permit the remove_image
attribute:
posts_controller.rb
params.require(:post).permit(:title, :trunk, :epitome, :remove_image, :image_cache)
That'southward it! To remove an epitome manually, apply theremove_image!
method:
@mail service.remove_image!
Uploading From a Remote Location
Carrierwave also provides a very cool feature out of the box: the ability to upload files from remote locations by their URL. Permit'southward introduce this power at present by adding a new field and permitting the corresponding attribute:
views/shared/_form.html.erb
<%= f.text_field :remote_image_url %> <small>Enter URL to an image</small>
posts_controller.rb
params.crave(:post).permit(:championship, :body, :image, :remove_image, :image_cache, :remote_image_url)
How absurd is that? Y'all don't need to make any changes at all, and you lot can test this feature right away!
Working With Multiple Uploads
Suppose we want our post to take multiple attachments bachelor. With the current setup it is non possible, but luckily, Carrierwave supports such a scenario likewise. To implement this feature, you lot need to add together either a serialized field (for SQLite) or a JSON field (for Postgres or MySQL). I prefer the latter option, so let'due south switch to a new database adapter now. Remove the sqlite3 gem from the Gemfile and add pg instead:
Gemfile
precious stone 'pg'
Install it:
bundle install
Modify the database configuration like this:
config/database.yml
default: &default adapter: postgresql pool: 5 timeout: 5000 development: <<: *default database: upload_carrier_dev username: 'YOUR_USER' countersign: 'YOUR_PASSWORD' host: localhost
Create the corresponding Postgres database, and and then generate and apply the migration:
rails grand migration add_attachments_to_posts attachments:json track db:drift
If you prefer to stick with SQLite, follow the instructions listed in Carrierwave's documentation.
At present mount the uploaders (notation the plural form!):
model/post.rb
mount_uploaders :attachments, ImageUploader
I am using the same uploader for attachments, but of course y'all tin can generate a new one with a different configuration.
Add the multiple file field to your form:
views/shared/_form.html.erb
<div> <%= f.label :attachments %> <%= f.file_field :attachments, multiple: truthful %> </div>
Every bit long as the attachments
field is going to incorporate an array, it should exist permitted in the following style:
posts_controller.rb
params.require(:post).let(:title, :body, :paradigm, :remove_image, :image_cache, :remote_image_url, attachments: [])
Lastly, you may iterate over the mail's attachments and display them as usual:
views/shared/prove.html.erb
<% if @mail service.attachments? %> <ul> <% @post.attachments.each do |attachment| %> <li><%= link_to(image_tag(attachment.pollex.url, alt: 'Image'), zipper.url, target: '_blank') %></li> <% end %> </ul> <% end %>
Note that each zipper is going to have a thumbnail as configured in our ImageUploader
. Dainty!
Using Cloud Storage
Sticking with file storage is not always convenient and/or possible as, for instance, on Heroku information technology is not possible to store custom files. Therefore you might inquire how to ally Carrierwave with Amazon S3 cloud storage? Well, that's a pretty easy task as well. Carrierwave depends on the fog-aws gem to implement this characteristic:
Gemfile
jewel "fog-aws"
Install it:
bundle install
Let's create an initializer for Carrierwave and configure the deject storage globally:
config/initializers/carrierwave.rb
CarrierWave.configure do |config| config.fog_provider = 'fog/aws' config.fog_credentials = { provider: 'AWS', aws_access_key_id: ENV['S3_KEY'], aws_secret_access_key: ENV['S3_SECRET'], region: ENV['S3_REGION'], } config.fog_directory = ENV['S3_BUCKET'] end
There are some other options available, which can be found in the documentation.
I am using the dotenv-rails gem to set up the environment variables in a secure mode, merely yous may choose any other option. However, brand sure that your S3 key pair is not available publicly, because otherwise anyone can upload anything to your saucepan!
Next, replace the storage :file
line with:
uploaders/image_uploader.rb
storage :fog
Autonomously from S3, Carrierwave supports uploads to Google Storage and Rackspace. These services are easy to gear up as well.
Conclusion
This is it for today! We have covered all the major features of Carrierwave, and now you can first using it in your projects. Information technology has some additional options available, and so do browse the documentation.
If you are stuck, don't hesitate to post your questions. Also, it might be useful to have a peek into Carrierwave's wiki, which hosts useful "how to" articles answering many common questions.
And so I give thanks you for staying with me, and happy coding!
Did you find this post useful?
thompsonabsontrythe42.blogspot.com
Source: https://code.tutsplus.com/articles/uploading-with-rails-and-carrierwave--cms-28409
0 Response to "Rails Carrierwave Uploading to Aws but Not Displaying"
Post a Comment