I am a beginner of programming learning for about 3 months for the first time, but I would like to keep a memorandum of what I learned in the Rails tutorial. This article was written with reference to the Rails tutorial.
The most convenient way to upload files in Rails is to use a feature called Active Storage built into Rails. If you use this, you can easily create an image posting function etc. with a form. By using Active Storage in your application, you can use ImageMagick to transform image uploads, generate non-image upload image representations such as PDFs and videos, and extract metadata from arbitrary files.
$ rails active_storage:install
$ rails db:migrate
This migration produces two tables named active_storage_blobs
and active_storage_attachments
. ` active_storage_blobsis the table where the actually uploaded files are stored, and
active_storage_attachments` is the intermediate table.
This time, suppose you add one image to the Micropost model.
micropost.rb
class Micropost < ApplicationRecord
has_one_attached :image
end
: image is the file name, please use whatever you like, such as: photo,: avatar, etc. according to the purpose of the file.
The has_one_attached
method is used to associate the specified model with the uploaded file. In this case, specify image to associate with the Micropost
model.
Then add the file_fiele
tag to the micropost form.
ruby:app/views/shared/_micropost_form.html.erb
<%= form_with model: @micropost, local: true do |f| %>
<%= f.text_area :content %>
<%= f.file_field :image %>
<%= f.submit %>
<% end %>
Finally, update the Microposts
controller so that you can add images to the newly created micropost
object. The Actuve Storage API
provides a attach
method for that, which you can use. Specifically, in the create
action of the Microposts
controller, attach the uploaded image to the @ micropost
object. To allow this upload, you also need to update the micropost_params
method to add: image
to the allowed attributes list so that it can be updated via the web.
microposts_controller.rb
class MicropostsController < ApplicationController
def create
@micropost = current_user.microposts.build(micropost_params)
@micropost.image.attach(params[:micropost][:image])
if @micropost.save
flash[:success] = "Micropost created!"
redirect_to root_url
else
@feed_items = current_user.feed.paginate(page: params[:page])
render 'static_pages/home'
end
end
private
def micropost_params
params.require(:micropost).permit(:content, :image)
end
end
Once the image is uploaded, you can use the micropost partial'image_taghelper to draw (render) the associated
micropost.image. Also, since the post may or may not have an image attached (only text without an image, etc.), is it a post with an image attached using a method that returns a logical value of
attached?`? Check if the post is not attached, and if an image is attached, display the image.
ruby:app/views/microposts/_micropost.html.erb
<%= image_tag micropost.image if micropost.image.attached? %>
The above uploader has some noticeable drawbacks. In particular, there are no restrictions on uploaded images, so if a user raises a huge file or an invalid file, problems will occur. To fix this shortcoming, implement validation for image size and format. Active Storage does not natively support these formatting and validation features. So add a gem for Active Storage validation.
Gemfile
gem 'active_storage_validations'
Don't forget to run bundle install.
$ bundle install
If you read the documentation for this gem, you'll see that you can validate the image by inspecting the content_type
as follows:
content_type: { in: %w[image/jpeg image/gif image/png],
message: "must be a valid image format" }
This will check for images that correspond to the supported image formats.
Similarly, the file size can be validated as follows:
size: { less_than: 5.megabytes,
message: "should be less than 5MB" }
This time, we will limit the size of the image to 5MB. Add these validations to your Micropost model.
micropost.rb
class Micropost < ApplicationRecord
validates :image, content_type: { in: %w[image/jpeg image/gif image/png],
message: "must be a valid image format" },
size: { less_than: 5.megabytes,
message: "should be less than 5MB" }
end
In addition to these validations, we will also add a mechanism to check the size and format of image uploads on the client side (that is, the browser). Let's add a bit of JavaScript
(specifically jQuery
) and get an alert when the image the user is trying to upload is too big (this way the user wastes time uploading). You don't have to, and the load on the server is lighter).
ruby:app/views/shared/_micropost_form.html.erb
<script type="text/javascript">
$("#micropost_image").bind("change", function() {
var size_in_megabytes = this.files[0].size/1024/1024;
if (size_in_megabytes > 5) {
alert("Maximum file size is 5MB. Please choose a smaller file.");
$("#micropost_image").val("");
}
});
</script>
This will warn you with the alert
method if the file size is too large.
Finally, you can use the accept
parameter in the file_field
input tag to tell the user that you can only upload in a valid format.
ruby:app/views/shared/_micropost_form.html.erb
<%= f.file_field :image, accept: "image/jpeg,image/gif,image/png" %>
Only the valid image formats are initially selectable, and the other file types are grayed out.
To resize an image, you need a program to manipulate the image. This time we will use a program called ImageMagick
, so install it in your development environment. (If your production environment is Heroku
, you can already use` ImageMagick in your production environment.)
In the cloud IDE, you can install this program with the following command:
$ sudo apt-get -y install imagemagick
If you are not using a cloud IDE or equivalent Linux environment, the procedure for installing ImagiMagick will change depending on your environment. For example, if you are using a Mac, you must have Homebrew installed before you can install it with the brew install imagemagick command.
How to install for Homebrew
$ brew install imagemagick
Next, we need some gems for image processing.
It requires image_processing gem
and mini_magick gem
, which is a Ruby ImageMagick processor.
Gemfile
gem 'image_processing'
gem 'mini_magick'
$ bundle install
You'll probably need to restart the Rails server
after installation.
You will be able to create converted images with the variant
method provided by Active Storage. In particular, use the resize_to_limit
option to constrain the width and height of the image so that it does not exceed 500 pixels, as shown below.
image.variant(resize_to_limit: [500, 500])
Put this code in the display_image method separately for convenience.
micropost.rb
#Returns a resized image for display
def display_image
imge.variant(resize_to_limit: [500, 500])
end
Now you can use display_image with micropost partials.
ruby:app/views/microposts/_micropost.html.erb
<%= image_tag micropost.display_image if micropost.image.attached? %>
Recommended Posts