An Interest In:
Web News this Week
- April 20, 2024
- April 19, 2024
- April 18, 2024
- April 17, 2024
- April 16, 2024
- April 15, 2024
- April 14, 2024
Rails Image Upload Using Dragonfly
File uploading is an important feature in web applications. Aside from enabling users to upload profile pictures, the use of file uploading features varies. I have shown you how to enable file uploading in your Rails application using different gems. Today I will be showing you how to do the same using Dragonfly.
Dragonfly is a highly customizable Ruby gem for handling images and other attachments and is already in use on thousands of websites.
You may be given a task to enable file uploading in a Rails application and may not want to make use of the other gems that are out there. You can give Dragonfly a shot, and you will definitely not regret it.
In this tutorial you will create a simple Rails application; I named mine Dragon-Uploader. The application will have just one feature: image uploading.
Installing ImageMagick
To use dragonfly, you need ImageMagick installed on your machine. Follow any of the steps below, depending on your operating system.
Mac Users:
brew install imagemagick
Ubuntu users:
sudo apt-get install imagemagick
Rails Application Generation
rails new dragon-uploader -T
The -T
option ensures that your Rails application is generated without the default testing suite.
Go to your Gemfile
and add the dragonfly
gem.
#Gemfile
gem 'dragonfly', '~> 1.0', '>= 1.0.12'
Do not forget to bundle.
bundle install
Let's generate our controller.
rails generate controller Photos
Integrating Dragonfly
The first step to integrating Dragonfly into your Rails application is to run the dragonfly generation command from your terminal.
rails generate dragonfly
This will create an initializer file for Dragonfly in your config/initializers
folder.
The file looks like this:
#config/intializers/dragonfly.rb
require 'dragonfly'
# Configure
Dragonfly.app.configure do
plugin :imagemagick
secret "e83b8affbf1c807c7788c07d27e70e79fb0459f8e2c4375b59e60a3da11631e5"
url_format "/media/:job/:name"
datastore :file,
root_path: Rails.root.join('public/system/dragonfly', Rails.env),
server_root: Rails.root.join('public')
end
# Logger
Dragonfly.logger = Rails.logger
# Mount as middleware
Rails.application.middleware.use Dragonfly::Middleware
# Add model functionality
if defined?(ActiveRecord::Base)
ActiveRecord::Base.extend Dragonfly::Model
ActiveRecord::Base.extend Dragonfly::Model::Validations
end
rails generate model Photo
#app/models/photo.rb
class Photo < ActiveRecord::Base
dragonfly_accessor :image
end
Dragonfly provides an accessor that you will need to add to your model. With this you can read and write images.
Now navigate to your migration file and add columns.
#xxx_create_photos.rb
class CreatePhotos < ActiveRecord::Migration
def change
create_table :photos do |t|
t.string :image_uid
t.string :title
t.timestamps null: false
end
end
end
Note: If you are making use of avatar
and not image
as I did above, you should change the column to avatar_uid
.
Migrate your database:
rake db:migrate
Set up your PhotosController
with the necessary actions to upload an image. It should look like this:
#app/controllers/photos_controller.rb
class PhotosController < ApplicationController
def index
@photos = Photo.all
end
def new
@photo = Photo.new
end
def create
@photo = Photo.new(photo_params)
if @photo.save
redirect_to photos_path
else
render :new
end
end
private
def photo_params
params.require(:photo).permit(:image, :title)
end
end
You will need to configure your routes.
For now, add routes to the three actions you have created.
#config/routes.rb
Rails.application.routes.draw do
resource :photos only: [:index, :new, :create]
root to: "photos#index"
end
You need to set up your views as I have below:
#app/views/photos/index.html.erb
<h2>Photos</h2>
<p id="notice"><%= notice %></p>
<table>
<thead>
<tr>
<th>Title</th>
<th>Image</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @photos.each do |photo| %>
<tr>
<td><%= photo.title %></td>
<td><%= link_to image_tag(photo.image.thumb('100x100').url), photo.image.url %></td>
<td><%= link_to 'Show', photo %></td>
<td><%= link_to 'Edit', edit_photo_path(photo) %></td>
<td><%= link_to 'Destroy', photo, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
#app/views/photos/new.html.erb
<%= form_for @photo do |f| %>
<div>
<%= f.label :title %>
<%= f.text_field :title %>
</div>
<div>
<%= f.label :image %>
<%= f.file_field :image %>
</div>
<div>
<%= f.submit :submit %>
</div>
<% end %>
We will come back to these views later.
Validations
For security purposes, you do not want to grant your users the privilege of uploading files of any type. Dragonfly provides you with the necessary methods for this in your initializers.
#config/initializers/dragonfly.rb
# Add model functionality
if defined?(ActiveRecord::Base)
ActiveRecord::Base.extend Dragonfly::Model
ActiveRecord::Base.extend Dragonfly::Model::Validations
end
Now edit your photo model to look like what I have below:
#app/models/photo.rb
class Photo < ActiveRecord::Base
dragonfly_accessor :image
#title validation
validates_presence_of :title
#image validations
validates_presence_of :image
validates_size_of :image, maximum: 400.kilobytes,
message: "should not be more than 400KB", if: :image_changed?
validates_property :format, of: :image, in: ['jpeg', 'png', 'gif'],
message: "the formats allowed are: .jpeg, .png, .gif", if: :image_changed?
end
Here is a full list of the validations Dragonfly offers:
class Photo
extend Dragonfly::Model::Validations
validates_presence_of :image
validates_size_of :image, maximum: 500.kilobytes
# Check the file extension
validates_property :ext, of: :image, as: 'jpg'
# ..or..
validates_property :mime_type, of: :image, as: 'image/jpeg'
# ..or actually analyse the format with imagemagick..
validates_property :format, of: :image, in: ['jpeg', 'png', 'gif']
validates_property :width, of: :image, in: (0..400), message: "é demais cara!"
# ..or you might want to use image_changed? method..
validates_property :format, of: :image, as: 'png', if: :image_changed?
end
You can read more about it in the Dragonfly documentation.
You should also consider giving your users the option to edit their saved images. To do this, we need to add two action methods to our PhotosController
and create an edit page in our views. You might want to add the delete and show action while you're at it, as I have below:
#app/controllers/photos_controller.rb
class PhotosController < ApplicationController
before_action :set_photos, only: [:show, :edit, :update, :destroy]
def index
@photos = Photo.all
end
def new
@photo = Photo.new
end
def create
@photo = Photo.new(photo_params)
if @photo.save
redirect_to @photo
else
render :new
end
end
def show
end
def edit
end
def update
if @photo.update(photo_params)
redirect_to @photo, notice: "photo successfully updated"
else
render :edit
end
end
def destroy
@photo.destroy
redirect_to photos_url, notice: 'photo was successfully destroyed.'
end
private
def photo_params
params.require(:photo).permit(:image, :title)
end
def set_photos
@photo = Photo.find(params[:id])
end
end
#app/views/photos/edit.html.erb
<%= form_for @photo do |f| %>
<% if @photo.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@photo.errors.count, "error") %> prohibited this photo from being saved:</h2>
<ul>
<% @photo.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div>
<%= f.label :title %>
<%= f.text_field :title %>
</div>
<div>
<%= f.label :image %>
<%= f.file_field :image %>
</div>
<div>
<%= f.submit :submit %>
</div>
<% end %>
<%= link_to "Show", @photo %> |
<%= link_to "Back", photos_path %>
#app/views/photos/show.html.erb
<div>
<strong>Title:</strong>
<%= @photo.title %>
</div>
<div>
<strong>Image:</strong>
<%= image_tag @photo.image.thumb('400x200#').url if @photo.image_stored? %>
</div>
<%= link_to 'Edit', edit_photo_path(@photo) %> |
<%= link_to 'Back', photos_path %>
If you try to access the show or edit page, you will be presented with errors. This is because we restricted the route to :new, :index, and :update
. Now go ahead and change that; it should look like this:
#config/routes.rb
Rails.application.routes.draw do
resources :photos
root to: "photos#index"
end
Conclusion
At this point, you can now integrate Dragonfly into your Rails application. Be sure to check out the documentation if you want to try more features not mentioned here. I hope you enjoyed it.
Remember, you can always add feedback, questions, and comments in the form below.
Original Link:
TutsPlus - Code
Tuts+ is a site aimed at web developers and designers offering tutorials and articles on technologies, skills and techniques to improve how you design and build websites.More About this Source Visit TutsPlus - Code