v1.7
版本发布时间: 2023-02-19 19:10:25
the-teacher/rails7-startkit最新发布版本:v2.1(2023-09-18 15:15:47)
Rails 7. Start Kit
and ActiveStorage
Rails 7 Start Kit — Dockerized Rails App with the most popular preinstalled tools.
Install and Run Ruby on Rails
now!
Copy & Paste in your terminal
git clone https://github.com/the-teacher/rails7-startkit.git && \
cd rails7-startkit && \
bin/setup
I've done a mistake when I've chosen ActiveStorage
I didn't write any rails code last 5 or 6 years. I've heard that now Rails has a default solution to upload files. Moreover I saw the following message on the paperclip page
Since that moment it was clear to me that I have to use ActiveStorage
for image uploading. Probably all other uploading solutions just died for rails.
Intuitively I expected that ActiveStorage
will help me to do all the same things that I did for paperclip or carrierwave. Storage is just storage. What can be wrong with it?
When I have installed ActiveStorage
I found that it is impossible to setup a human-friendly path for files' location. All file paths and files look like that.
I was confused, and looks like I'm not the first person who was. Link 1 Link 2
I looked for solutions or workarounds. I asked people in different RoR communities, and I found that not so much people understand why it is so.
Some people just switch to other solutions like carrierwave or shrine.
After a small investigation I should say the following:
ActiveStorage is a cloud solution
- If you read a definition: Active Storage makes it simple to upload and reference files in cloud services like Amazon S3, Google Cloud Storage, or Microsoft Azure Storage, and attach those files to Active Records.
- You should accept that Active Storage will use not a human-friendly paths for your files
- You should accept that Active Storage will use not a human-friendly file names
- You should accept that Active Storage will stream your files via the Application
If you want to to have human-friendly locations and file names to navigate on it sometimes and feel a full control over the situation -- Active Storage is a mistake. You probably should use something else. I wanted just a "typical" file uploading solution with a friendly file structure like paperclip or carrierwave, but AS is a bit different. I needed time to accept it.
:warning: I've done a mistake when I've chosen Active Storage as a typical file upload solution. It is not so simple as I expected.
I relied on my intuition, but not on the description of the library. I think Active Storage should be renamed to Active Cloud Storage to avoid confusing people like me, who like to do something but not to read a boring definitions on a Readme page 😄
Conclusion
Now when I see all aspects and boundaries of this solution I can choose exactly what I need for my specific cases in future. I think sometimes I can even use multiple solutions in the same app for different models and goals.
Using ActiveStorage
for User Avatar in 10 steps
Step 1
Like it was described in the official documentation I did
For generation of database migrations and migrating
$ bin/rails active_storage:install
$ bin/rails db:migrate
No need modify config/storage.yml
. We will go with default settings
test:
service: Disk
root: <%= Rails.root.join("tmp/storage") %>
local:
service: Disk
root: <%= Rails.root.join("storage") %>
Step 2
Now it is time to improve app/models/user.rb and add an attachment
class User < ApplicationRecord
# img_path = Rails.root.join('public/Rails7.StartKit.jpg')
# u = User.first
# u.avatar.attach(io: File.open(img_path), filename: 'avatar.jpg')
#
# u.avatar.purge
has_one_attached :avatar
...
end
As you see I left some commands in the comments to check the functionality from Rails Console
Step 3
Checking that everything works from Rails Console
From the root of the application
$ rails c
Now when you are in Rails Console:
img_path = Rails.root.join('public/Rails7.StartKit.jpg')
u = User.first
u.avatar.attach(io: File.open(img_path), filename: 'avatar.jpg')
In the project in storage
folder you will see something like that:
Everything works!
Step 4
Now we ned to modify the app. We use Devise
and we need to integrate our uploading with it. No problems!
We create a controller for User
model.
I created the file app/controllers/users_controller.rb
manually. It is simple and I do not need any code generator.
# frozen_string_literal: true
class UsersController < ApplicationController
before_action :authenticate_user!, except: :profile
def profile; end
def update
current_user.update(user_params)
redirect_to profile_user_path, notice: 'Avatar is uploaded'
end
private
def user_params
params.require(:user).permit(:avatar)
end
end
Step 5
To have an access to this controller I need routing. config/routes.rb
Rails.application.routes.draw do
devise_for :users
root 'demo#index'
...
resource :user, only: [:update] do
get :profile
end
end
Step 6
I need a link to my profile page
<div class="examples">
...
<%= link_to "Upload Avatar", profile_user_path, class: 'example-item' %>
</div>
Step 7
When I'm not a logged in user I should not have an access to uploading, because I do not know a user to which I'm going to attach my avatar.
In the file app/views/users/profile.html.erb
<% unless user_signed_in? %>
<p>
You can not upload an avatar until user is logged in:
<%= link_to "Sign In", new_user_session_path %>
</p>
<p>
email: <b>admin@rails-start.com</b>
</p>
<p>
password: <b>qwerty123</b>
</p>
<% end %>
If you have passed logging process you will see
<% if user_signed_in? %>
<p>
Current user: <%= current_user.email %> |
<%= link_to "Sign Out", destroy_user_session_path%>
</p>
<% if current_user.avatar.attached? %>
<%= image_tag current_user.avatar, class: :user_avatar %>
<% end %>
<%= form_for current_user, method: :patch do |form| %>
<p><%= form.file_field :avatar %></p>
<p><%= form.submit "Upload" %></p>
<% end %>
<% end %>
Step 8
Now you can upload a new file and check how it works.
Step 9
You can visit web inspector and check how actually you image was received. Definitely Rails controller was involved into this process.
Step 10
Company JetBrains found my project interesting and I was given a licence to use RubyMine for my project. They didn't ask about anything in return, but I would like to acknowledge them. I found their IDE really helpful.
That is it!
👉 Subscribe to the project to know about most recent updates.
Happy coding with Rails 7. Start Kit