Javascript Image Upload Ajax Tutorial Rails Carrierwave
Read Time: 11 mins Languages:
This is another article in the "Uploading with Rails" series. Today we are going to run into Carrierwave—ane of the virtually popular file uploading solutions for Rails. I like Carrierwave because it is easy to get started, it has lots of features out of the box, and information technology provides dozens of "how to" articles written past the members of the community, so yous won't become lost.
In this commodity, yous 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
- Innovate multiple file uploads
- Add back up for cloud storage
The source lawmaking for this commodity is available on GitHub. Enjoy reading!
Laying the Foundations
As always, start by creating a new Rails awarding:
runway new UploadingWithCarrierwave -T
For this demo I'll exist using Rails v.0.2. Delight note that Carrierwave one supports only Rails 4+ and Ruby 2. If you are still riding on Runway 3, and then hook up Carrierwave version 0.xi.
To run across Carrierwave in action, nosotros are going to create a very simple blogging application with a sole Postal service
model. It will have the following master attributes:
-
title
(string
) -
trunk
(text
) -
paradigm
(string
)—this field is going to contain an image (a file's name, to be precise) attached to the post
Generate and apply a new migration:
rails grand model Mail championship:string trunk:text prototype:string runway db:migrate
Fix some routes:
config/routes.rb
resources :posts root to: 'posts#index'
Also, create a very basic controller:
posts_controller.rb
class PostsController < ApplicationController before_action :set_post, but: [:show, :edit, :update] def index @posts = Mail.lodge('created_at DESC') stop def bear witness end def new @postal service = Post.new end def create @post = Post.new(post_params) if @post.relieve redirect_to posts_path else return :new end end def edit end def update if @mail service.update_attributes(post_params) redirect_to post_path(@post) else render :edit cease end private def post_params params.require(:postal service).permit(:title, :body, :image) end def set_post @post = Post.find(params[:id]) stop end
At present permit's craft the alphabetize view:
views/posts/alphabetize.html.erb
<h1>Posts</h1> <%= link_to 'Add mail service', new_post_path %> <%= render @posts %>
And the respective partial:
views/posts/_post.html.erb
<h2><%= link_to postal service.title, post_path(post) %></h2> <p><%= truncate(mail service.body, length: 150) %></p> <p><%= link_to 'Edit', edit_post_path(mail) %></p> <hr>
Here I am using the Runwaytruncate
method to display only the first 150 symbols from the post. Before we create other views and a form partial, let'due south firstly integrate Carrierwave into the application.
Integrating Carrierwave
Driblet in a new gem into the Gemfile:
Gemfile
gem 'carrierwave', '~> one.0'
Run:
bundle install
Carrierwave stores its configuration withinuploadersthat are included into your models. To generate an uploader, use the following command:
rails generate uploader Image
At present, within app/uploaders, you lot volition find a new file called image_uploader.rb. Note that it has some useful comments and examples, so you may use it to become started. In this demo we will use ActiveRecord, but Carrierwave also has support for Mongoid, Sequel, and DataMapper.
Next, we need to include or mount this uploader into the model:
models/mail service.rb
mount_uploader :image, ImageUploader
The uploader already has sane default settings, but at the very least nosotros need to choose where the uploaded files will be stored. For now, allow'due south utilize file storage:
uploaders/image_uploader.rb
storage :file
Past default, files will be placed inside the public/uploads directory, so it is best to exclude it from the version control system:
.gitignore
public/uploads
You may also alter thestore_dir
method within your uploader to cull some other location.
At this point, we tin can create a new view and a form fractional to start uploading files:
views/posts/new.html.erb
<h1>Add mail service</h1> <%= render 'form', post: @post %>
views/posts/_form.html.erb
<%= form_for mail exercise |f| %> <div> <%= f.label :title %> <%= f.text_field :title %> </div> <div> <%= f.label :body %> <%= f.text_area :body %> </div> <div> <%= f.label :paradigm %> <%= f.file_field :image %> </div> <%= f.submit %> <% end %>
Note that the PostsController
does non need to be modified equally we already permitted the paradigm
attribute.
Lastly, create the edit view:
views/posts/edit.html.erb
<h1>Edit mail service</h1> <%= return 'grade', mail: @post %>
That's it! You may kicking the server and try to create a mail service with an prototype. The problem is that this prototype is not visible anywhere, so let's proceed to the side by side department and add a bear witness page!
Displaying Images
And so, the only view we accept not created yet is bear witness. Add it now:
views/posts/show.html.erb
<%= link_to 'All posts', posts_path %> <h1><%= @post.title %></h1> <%= image_tag(@mail service.image.url, alt: 'Image') if @post.image? %> <p><%= @post.body %></p> <p><%= link_to 'Edit', edit_post_path(@post) %></p>
As you tin can see, displaying an attachment is actually easy: all you need to do is say @mail service.image.url
to take hold of an epitome's URL. To get a path to the file, use thecurrent_path
method. Annotation that Carrierwave likewise provides an epitome?
method for u.s.a. to check whether an attachment is present at all (the image
method itself will never render zilch
, even if the file is not present).
At present, after navigating to a mail, yous should run into an image, simply it might appear likewise large: later on all, we are not restricting dimensions anywhere. Of grade, we could accept scaled the image downwards with some CSS rules, but it is much better to generate a thumbnail afterwards the file has been uploaded. This, notwithstanding, requires some additional steps.
Generating Thumbnails
In gild to crop and scale images, we need a separate tool. Out of the box Carrierwave has support for RMagick and MiniMagick gems that, in turn, are used to manipulate images with the help of ImageMagick. ImageMagick is an open-source solution allowing you to edit existing images and generate new ones, then earlier proceeding you demand to download and install it. Next, you are free to option either of the two gems. I'll stick with MiniMagick, because information technology is much easier to install and it has better support:
Gemfile
gem 'mini_magick'
Run:
bundle install
Then include MiniMagick into your uploader:
uploaders/image_uploader.rb
include CarrierWave::MiniMagick
At present 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 just means that additional files based on the original attachment will be created with, for example, different dimensions or formats. Innovate a new version called thumb
:
uploaders/image_uploader.rb
version :pollex do procedure resize_to_fill: [350, 350] terminate
You may have as many versions as you lot like and, what'due south more, versions can even be built on top of other ones:
uploaders/image_uploader.rb
version :small_thumb, from_version: :thumb do process resize_to_fill: [twenty, twenty] end
If you accept already uploaded some images, they won't have thumbnails available. This is not a problem, though, equally you can copy them from the Rail console:
rails c Post.find_each {|post| post.image.recreate_versions!(:thumb) if post.prototype?}
Lastly, display your thumbnail with a link to the original image:
views/posts/show.html.erb
<%= link_to(image_tag(@post.image.pollex.url, alt: 'Image'), @postal service.image.url, target: '_blank') if @post.prototype? %>
Boot the server and observe the result!
Calculation Validations
Currently our uploading works, but we're not validating user input at all, which is, of course, bad. As long as we desire to work only with images, permit's whitelist .png, .jpg and .gif extensions:
uploaders/image_uploader.rb
def extension_whitelist %w(jpg jpeg gif png) end
You may also add content type checks past defining a content_type_whitelist
method:
uploaders/image_uploader.rb
def content_type_whitelist /paradigm\// finish
Alternatively, it is possible to blacklist some file types, for example executables, by defining thecontent_type_blacklist
method.
Apart from checking a file'south type and extension, allow'southward enforce it to be less than 1 megabyte. To do it, we'll crave an additional jewel supporting file validations for ActiveModel:
Gemfile
gem 'file_validators'
Install it:
packet install
At present introduce the desired validations (notation that I am besides adding checks for the title
and body
attributes):
models/post.rb
validates :title, presence: true, length: {minimum: 2} validates :trunk, presence: true validates :image, file_size: { less_than: 1.megabytes }
The adjacent thing to do is to add I18n translations for Carrierwave's error messages:
config/locales/en.yml
en: errors: messages: carrierwave_processing_error: "Cannot resize image." carrierwave_integrity_error: "Not an prototype." carrierwave_download_error: "Couldn't download image." extension_whitelist_error: "You are not immune to upload %{extension} files, allowed types: %{allowed_types}" extension_blacklist_error: "You are non allowed to upload %{extension} files, prohibited types: %{prohibited_types}"
Currently, we do non brandish validation errors anywhere, so allow'south create a shared fractional:
views/shared/_errors.html.erb
<% if object.errors.any? %> <h3>Some errors were found:</h3> <ul> <% object.errors.full_messages.each do |message| %> <li><%= bulletin %></li> <% finish %> </ul> <% end %>
Utilise this fractional inside the grade:
views/posts/_form.html.erb
<%= return 'shared/errors', object: postal service %>
At present try to upload some invalid files and observe the result. It should piece of work, simply if you cull a valid file and do not fill in the title or body, and then the checks volition still fail and an error volition be displayed. Withal, the file field will be cleared out and the user will need to choose the image again, which is not very convenient. To set it, we demand to add another field to the form.
Persisting Files Across Requests
Persisting files beyond form redisplays is actually quite easy. All you need to do is add a new hidden field and permit it inside the controller:
views/shared/_form.html.erb
<%= f.label :epitome %> <%= f.file_field :image %><br> <%= f.hidden_field :image_cache %>
posts_controller.rb
params.require(:post).let(:championship, :body, :image, :image_cache)
Now the image_cache
will be populated automatically and the epitome won't be lost. It may be helpful to display a thumbnail too so that user understands the epitome was processed successfully:
views/shared/_form.html.erb
<% if mail service.image? %> <%= image_tag post.image.thumb.url %> <% finish %>
Removing Images
Some other very mutual characteristic is the power to remove attached files when editing a record. With Carrierwave, implementing this feature is not a problem. Add a new checkbox to the form:
views/shared/_form.html.erb
<% if mail service.paradigm? %> <%= image_tag post.image.pollex.url %> <div> <%= label_tag :remove_image do %> Remove paradigm <%= f.check_box :remove_image %> <% end %> </div> <% end %>
And permit the remove_image
aspect:
posts_controller.rb
params.require(:post).let(:title, :torso, :image, :remove_image, :image_cache)
That's it! To remove an image manually, use theremove_image!
method:
@postal service.remove_image!
Uploading From a Remote Location
Carrierwave also provides a very absurd feature out of the box: the ability to upload files from remote locations by their URL. Permit's introduce this ability now by adding a new field and permitting the corresponding aspect:
views/shared/_form.html.erb
<%= f.text_field :remote_image_url %> <small>Enter URL to an image</small>
posts_controller.rb
params.crave(:mail).permit(:championship, :body, :image, :remove_image, :image_cache, :remote_image_url)
How cool is that? Y'all don't need to brand any changes at all, and you can test this characteristic right away!
Working With Multiple Uploads
Suppose we desire our mail service to accept multiple attachments bachelor. With the current setup it is non possible, but luckily, Carrierwave supports such a scenario too. To implement this feature, you demand to add either a serialized field (for SQLite) or a JSON field (for Postgres or MySQL). I prefer the latter option, so let's switch to a new database adapter now. Remove the sqlite3 gem from the Gemfile and add pg instead:
Gemfile
gem 'pg'
Install it:
bundle install
Modify the database configuration like this:
config/database.yml
default: &default adapter: postgresql pool: five timeout: 5000 development: <<: *default database: upload_carrier_dev username: 'YOUR_USER' password: 'YOUR_PASSWORD' host: localhost
Create the corresponding Postgres database, and so generate and utilise the migration:
track g migration add_attachments_to_posts attachments:json rails db:migrate
If you lot prefer to stick with SQLite, follow the instructions listed in Carrierwave'due south documentation.
Now mount the uploaders (note the plural form!):
model/mail service.rb
mount_uploaders :attachments, ImageUploader
I am using the same uploader for attachments, just of course y'all tin generate a new i with a different configuration.
Add together the multiple file field to your form:
views/shared/_form.html.erb
<div> <%= f.label :attachments %> <%= f.file_field :attachments, multiple: truthful %> </div>
As long as the attachments
field is going to contain an array, it should be permitted in the following way:
posts_controller.rb
params.crave(:post).permit(:title, :body, :image, :remove_image, :image_cache, :remote_image_url, attachments: [])
Lastly, you may iterate over the post's attachments and display them as usual:
views/shared/evidence.html.erb
<% if @mail.attachments? %> <ul> <% @post.attachments.each do |attachment| %> <li><%= link_to(image_tag(zipper.pollex.url, alt: 'Prototype'), attachment.url, target: '_blank') %></li> <% stop %> </ul> <% finish %>
Note that each attachment is going to have a thumbnail as configured in our ImageUploader
. Squeamish!
Using Cloud Storage
Sticking with file storage is not ever convenient and/or possible every bit, for example, on Heroku it is not possible to store custom files. Therefore you lot might ask how to marry 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
gem "fog-aws"
Install it:
bundle install
Let'due south create an initializer for Carrierwave and configure the cloud 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'] finish
There are some other options available, which can be plant in the documentation.
I am using the dotenv-rail gem to set the environment variables in a secure style, just you lot may choose any other selection. Even so, make sure that your S3 key pair is non bachelor publicly, because otherwise anyone tin can upload anything to your bucket!
Next, replace the storage :file
line with:
uploaders/image_uploader.rb
storage :fog
Apart from S3, Carrierwave supports uploads to Google Storage and Rackspace. These services are piece of cake to prepare up also.
Conclusion
This is it for today! We have covered all the major features of Carrierwave, and now you can start using information technology in your projects. Information technology has some boosted options bachelor, so do browse the documentation.
If y'all are stuck, don't hesitate to mail your questions. Also, it might be useful to take a peek into Carrierwave's wiki, which hosts useful "how to" articles answering many mutual questions.
So I thank you for staying with me, and happy coding!
Did you lot find this post useful?
Source: https://code.tutsplus.com/articles/uploading-with-rails-and-carrierwave--cms-28409
0 Response to "Javascript Image Upload Ajax Tutorial Rails Carrierwave"
Post a Comment