How to Upload Pictures Into Ruby Rails Database
Read Time: eleven mins Languages:
This is another article in the "Uploading with Rails" series. Today we are going to meet Carrierwave—one of the near popular file uploading solutions for Rail. 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 by the members of the customs, and so you won't get lost.
In this article, you lot will learn how to:
- Integrate Carrierwave into your Rails app
- Add validations
- Persist files beyond requests
- Remove files
- Generate thumbnails
- Upload files from remote locations
- Introduce multiple file uploads
- Add support for deject storage
The source code for this article is available on GitHub. Bask reading!
Laying the Foundations
Equally e'er, start by creating a new Runway application:
track new UploadingWithCarrierwave -T
For this demo I'll be using Rails 5.0.2. Please note that Carrierwave 1 supports only Rails four+ and Reddish two. If you lot are still riding on Rails three, then hook upwards Carrierwave version 0.11.
To see Carrierwave in action, nosotros are going to create a very simple blogging application with a sole Mail
model. It will accept the post-obit master attributes:
-
title
(cord
) -
trunk
(text
) -
image
(string
)—this field is going to contain an image (a file'due south name, to be precise) attached to the post
Generate and apply a new migration:
rails chiliad model Post title:cord trunk:text prototype:cord rails db:migrate
Set some routes:
config/routes.rb
resource :posts root to: 'posts#index'
Besides, create a very basic controller:
posts_controller.rb
class PostsController < ApplicationController before_action :set_post, only: [:show, :edit, :update] def alphabetize @posts = Post.order('created_at DESC') cease def show end def new @mail = Post.new end def create @post = Post.new(post_params) if @post.save redirect_to posts_path else render :new terminate finish def edit terminate def update if @post.update_attributes(post_params) redirect_to post_path(@post) else render :edit end stop private def post_params params.require(:mail service).allow(:title, :body, :paradigm) end def set_post @post = Post.detect(params[:id]) end stop
At present let's craft the index view:
views/posts/index.html.erb
<h1>Posts</h1> <%= link_to 'Add together post', new_post_path %> <%= render @posts %>
And the corresponding fractional:
views/posts/_post.html.erb
<h2><%= link_to post.title, post_path(post) %></h2> <p><%= truncate(post.torso, length: 150) %></p> <p><%= link_to 'Edit', edit_post_path(mail service) %></p> <hr>
Here I am using the Runwaytruncate
method to display only the first 150 symbols from the postal service. Before we create other views and a form partial, let'southward firstly integrate Carrierwave into the application.
Integrating Carrierwave
Driblet 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, employ the post-obit command:
track generate uploader Image
Now, within app/uploaders, yous will notice a new file called image_uploader.rb. Note that it has some useful comments and examples, then you may use it to get started. In this demo we will use ActiveRecord, merely Carrierwave also has back up for Mongoid, Sequel, and DataMapper.
Next, we need to include or mount this uploader into the model:
models/post.rb
mount_uploader :epitome, 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 at present, let's employ file storage:
uploaders/image_uploader.rb
storage :file
By default, files will be placed inside the public/uploads directory, so information technology is best to exclude it from the version control system:
.gitignore
public/uploads
You lot may also modify thestore_dir
method inside your uploader to cull some other location.
At this point, we can create a new view and a form fractional to outset uploading files:
views/posts/new.html.erb
<h1>Add post</h1> <%= render 'form', mail service: @mail service %>
views/posts/_form.html.erb
<%= form_for post practice |f| %> <div> <%= f.label :title %> <%= f.text_field :championship %> </div> <div> <%= f.label :body %> <%= f.text_area :body %> </div> <div> <%= f.characterization :image %> <%= f.file_field :image %> </div> <%= f.submit %> <% terminate %>
Note that the PostsController
does not need to exist modified as nosotros already permitted the image
aspect.
Lastly, create the edit view:
views/posts/edit.html.erb
<h1>Edit post</h1> <%= render 'course', postal service: @mail service %>
That'due south it! You may boot the server and try to create a post with an image. The trouble is that this epitome is not visible anywhere, so allow's proceed to the next section and add a evidence folio!
Displaying Images
So, the merely view we have not created even so is show. Add it now:
views/posts/show.html.erb
<%= link_to 'All posts', posts_path %> <h1><%= @post.championship %></h1> <%= image_tag(@postal service.image.url, alt: 'Prototype') if @post.prototype? %> <p><%= @post.trunk %></p> <p><%= link_to 'Edit', edit_post_path(@post) %></p>
As you can see, displaying an attachment is really easy: all y'all demand to do is say @mail service.image.url
to grab an image's URL. To get a path to the file, employ thecurrent_path
method. Notation that Carrierwave too provides an image?
method for u.s.a. to bank check whether an zipper is nowadays at all (the image
method itself will never return nil
, even if the file is not present).
Now, afterwards navigating to a mail service, you should see an image, but it might appear likewise large: after all, we are not restricting dimensions anywhere. Of course, we could take scaled the image downwardly with some CSS rules, but it is much meliorate to generate a thumbnail subsequently the file has been uploaded. This, notwithstanding, requires some additional steps.
Generating Thumbnails
In gild to ingather and scale images, we demand a separate tool. Out of the box Carrierwave has support for RMagick and MiniMagick gems that, in plough, are used to manipulate images with the help of ImageMagick. ImageMagick is an open-source solution allowing yous to edit existing images and generate new ones, so before proceeding you need to download and install information technology. Next, you are gratis to choice either of the two gems. I'll stick with MiniMagick, considering it is much easier to install and it has amend back up:
Gemfile
precious stone 'mini_magick'
Run:
package install
Then include MiniMagick into your uploader:
uploaders/image_uploader.rb
include CarrierWave::MiniMagick
Now nosotros simply need to innovate a new version to our uploader. The concept of versions (or styles) is used in many file uploading libraries; information technology only means that additional files based on the original zipper will be created with, for example, dissimilar dimensions or formats. Introduce a new version called thumb
:
uploaders/image_uploader.rb
version :thumb do process resize_to_fill: [350, 350] finish
You may have as many versions every bit yous like and, what'southward more, versions tin can even be built on top of other ones:
uploaders/image_uploader.rb
version :small_thumb, from_version: :pollex practise process resize_to_fill: [xx, 20] stop
If y'all have already uploaded some images, they won't accept thumbnails available. This is non a problem, though, as you tin re-create them from the Rails console:
rails c Mail.find_each {|post| post.image.recreate_versions!(:thumb) if mail service.image?}
Lastly, display your thumbnail with a link to the original image:
views/posts/show.html.erb
<%= link_to(image_tag(@post.image.thumb.url, alt: 'Epitome'), @postal service.image.url, target: '_blank') if @postal service.image? %>
Boot the server and discover the result!
Adding Validations
Currently our uploading works, only we're non validating user input at all, which is, of course, bad. Equally long every bit we want to piece of work merely with images, let'due south whitelist .png, .jpg and .gif extensions:
uploaders/image_uploader.rb
def extension_whitelist %west(jpg jpeg gif png) terminate
You may also add content type checks past defining a content_type_whitelist
method:
uploaders/image_uploader.rb
def content_type_whitelist /prototype\// end
Alternatively, it is possible to blacklist some file types, for example executables, by defining thecontent_type_blacklist
method.
Apart from checking a file's blazon and extension, let's enforce it to be less than 1 megabyte. To practice information technology, nosotros'll crave an additional gem supporting file validations for ActiveModel:
Gemfile
gem 'file_validators'
Install information technology:
parcel install
Now introduce the desired validations (note that I am as well adding checks for the championship
and body
attributes):
models/post.rb
validates :championship, presence: true, length: {minimum: 2} validates :trunk, presence: true validates :prototype, file_size: { less_than: one.megabytes }
The next thing to exercise is to add I18n translations for Carrierwave'south error letters:
config/locales/en.yml
en: errors: messages: carrierwave_processing_error: "Cannot resize image." carrierwave_integrity_error: "Non an image." 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 practise not display validation errors anywhere, so let's create a shared fractional:
views/shared/_errors.html.erb
<% if object.errors.whatsoever? %> <h3>Some errors were found:</h3> <ul> <% object.errors.full_messages.each practise |bulletin| %> <li><%= bulletin %></li> <% cease %> </ul> <% end %>
Employ this partial within the form:
views/posts/_form.html.erb
<%= render 'shared/errors', object: post %>
Now try to upload some invalid files and observe the upshot. It should work, only if you choose a valid file and do non fill in the championship or body, so the checks volition still neglect and an fault volition exist displayed. Notwithstanding, the file field volition be cleared out and the user volition need to choose the image again, which is not very convenient. To ready information technology, we demand to add together another field to the form.
Persisting Files Across Requests
Persisting files across 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 :image %> <%= f.file_field :paradigm %><br> <%= f.hidden_field :image_cache %>
posts_controller.rb
params.require(:post).permit(:title, :body, :image, :image_cache)
Now the image_cache
will be populated automatically and the image won't be lost. It may exist helpful to brandish a thumbnail every bit well and then that user understands the prototype was processed successfully:
views/shared/_form.html.erb
<% if postal service.prototype? %> <%= image_tag post.image.thumb.url %> <% finish %>
Removing Images
Some other very common feature is the ability to remove attached files when editing a record. With Carrierwave, implementing this characteristic is not a problem. Add a new checkbox to the form:
views/shared/_form.html.erb
<% if post.prototype? %> <%= image_tag post.image.thumb.url %> <div> <%= label_tag :remove_image do %> Remove prototype <%= f.check_box :remove_image %> <% end %> </div> <% finish %>
And allow the remove_image
attribute:
posts_controller.rb
params.require(:post).permit(:championship, :body, :prototype, :remove_image, :image_cache)
That's it! To remove an image manually, use theremove_image!
method:
@post.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. Let's introduce this ability now by adding a new field and permitting the respective attribute:
views/shared/_form.html.erb
<%= f.text_field :remote_image_url %> <small>Enter URL to an image</small>
posts_controller.rb
params.crave(:mail service).permit(:title, :torso, :image, :remove_image, :image_cache, :remote_image_url)
How cool is that? You don't demand to brand any changes at all, and y'all can examination this characteristic right abroad!
Working With Multiple Uploads
Suppose we want our mail service to have multiple attachments available. With the current setup information technology is not possible, but luckily, Carrierwave supports such a scenario besides. To implement this characteristic, you demand to add either a serialized field (for SQLite) or a JSON field (for Postgres or MySQL). I adopt the latter pick, so allow's 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: five timeout: 5000 evolution: <<: *default database: upload_carrier_dev username: 'YOUR_USER' password: 'YOUR_PASSWORD' host: localhost
Create the corresponding Postgres database, and so generate and apply the migration:
rail k migration add_attachments_to_posts attachments:json rails db:drift
If you prefer to stick with SQLite, follow the instructions listed in Carrierwave'south documentation.
Now mount the uploaders (note the plural class!):
model/post.rb
mount_uploaders :attachments, ImageUploader
I am using the same uploader for attachments, but of course y'all tin generate a new i 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: true %> </div>
Every bit long every bit the attachments
field is going to contain an assortment, it should be permitted in the following mode:
posts_controller.rb
params.require(:post).permit(:title, :torso, :image, :remove_image, :image_cache, :remote_image_url, attachments: [])
Lastly, yous may iterate over the mail service'due south attachments and display them as usual:
views/shared/show.html.erb
<% if @post.attachments? %> <ul> <% @post.attachments.each practise |zipper| %> <li><%= link_to(image_tag(zipper.thumb.url, alt: 'Epitome'), attachment.url, target: '_blank') %></li> <% end %> </ul> <% end %>
Note that each zipper is going to have a thumbnail every bit configured in our ImageUploader
. Nice!
Using Cloud Storage
Sticking with file storage is not always user-friendly and/or possible every bit, for example, on Heroku it is not possible to store custom files. Therefore you might inquire how to marry Carrierwave with Amazon S3 cloud storage? Well, that's a pretty easy task every bit well. Carrierwave depends on the fog-aws precious stone to implement this feature:
Gemfile
gem "fog-aws"
Install it:
bundle install
Permit'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'] cease
There are another options available, which can be found in the documentation.
I am using the dotenv-rails precious stone to gear up the surroundings variables in a secure way, but you may choose any other option. Nonetheless, make certain that your S3 key pair is not 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 easy to set upward every bit well.
Conclusion
This is information technology for today! We have covered all the major features of Carrierwave, and now you can start using it in your projects. It has some additional options available, so do browse the documentation.
If you are stuck, don't hesitate to mail your questions. Too, information technology might be useful to accept a peek into Carrierwave's wiki, which hosts useful "how to" articles answering many mutual questions.
And so I thank you for staying with me, and happy coding!
Did you notice this mail service useful?
mcclainstroardlean.blogspot.com
Source: https://code.tutsplus.com/articles/uploading-with-rails-and-carrierwave--cms-28409
Posting Komentar untuk "How to Upload Pictures Into Ruby Rails Database"