はじめに
Rails 6 に追加されそうな新機能を試す第15段。 今回のちょい足し機能は、 Active Storage
編です。
というか今回は Active Storage のバグフィックスじゃないかと思ってます。
Rails 5.2 では、model で validation のエラーが起ってもファイルがアップロードされていました。
Rails 6.0 では、model がDBに保存されるとファイルがアップロードされるようになっています。
実際に試した方がわかりやすいです。
記載時点では、Rails は 6.0.0.rc1 と 5.2.3 で確認しました。Rails 6.0.0.rc1 は gem install rails --prerelease
でインストールできます。
基本的な試し方は、5.2.3 でも 6.0.0rc1 でも同じです。
$ rails --version
Rails 6.0.0.rc1
Rails プロジェクトを作る
$ rails new sandbox6_0_0rc1
$ cd sandbox6_0_0rc1
scaffold で User を作る
$ bin/rails g scaffold User name
Active Storage を使う準備をする
$ bin/rails active_storage:install
User モデルを編集する
User モデルとアップロードファイル(今回は画像ファイル)を紐づけるため has_one_attached
を使います。
また、name に validation を追加します。
class User < ApplicationRecord
has_one_attached :avatar
validates :name, presence: true
end
view を編集する
ファイルをアップロードできるように _form.html.erb
を編集します。
avatar 用の form.file_field
を追加します。
<%= form_with(model: user, local: true) do |form| %>
...
<%= form.text_field :name %>
</div>
<div class="field">
<%= form.label :avatar %>
<%= form.file_field :avatar %>
</div>
<div class="actions">
...
<% end %>
アップロードされた画像ファイルを表示できるように show.html.erb
に image_tag
を追加します。
...
<%= @user.name %>
</p>
<p>
<strong>Avatar:</strong>
<% if @user.avatar.attached? %>
<%= image_tag @user.avatar %>
<% end %>
</p>
...
controller を編集する
ブラウザからパラメータとして渡されてくる avatar をUserモデルに渡せるように :avatar
を追加します。
private:
...
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:name, :avatar)
end
DBのmigration を実行する
$ bin/rails db:create db:migrate
rails s
を実行する
$ bin/rails s
動作確認する
ブラウザで http://localhost:3000/users/new にアクセスします。
アップロードする画像ファイルを選択します。
validation error となるように name は何も入力しません。
Create User
ボタンを押してみます。
Name can't be blank'
のエラーになります。
ここまでは、Rails 5.2.3 でも Rails 6.0.0rc1 でも同じです。
ここで、別のコンソールで、 storage
ディレクトリを確認してみましょう。
Rails 5.2.3 では、サブディレクトリができてファイルもできています。
$ ls -lR storage
storage:
total 4
drwxr-xr-x 3 suke suke 4096 5月 11 15:36 49
storage/49:
total 4
drwxr-xr-x 2 suke suke 4096 5月 11 15:36 gT
storage/49/gT:
total 12
-rw-r--r-- 1 suke suke 9502 5月 11 15:36 49gTM2NXg8UsKPVqTSuMNXCz
Rails 6.0.0rc1 では、サブディレクトリはありません。
$ ls -lR storage
storage:
total 0
Rails 5.2.3 では、登録画面で、ファイルを指定して、validation エラーを起こす度に、 storage
ディレクトリの中にファイルが増えていきます。
Rails 6.0.0rc1 では、DBに保存できた時に初めて、 storage
ディレクトリの中にファイルができます。
ソース
今回のソースは以下から参照できます。
https://github.com/suketa/rails6_0_0rc1/tree/try015_active_storage
参考情報
- What is new in Rails 6.0
- Store newly-uploaded files on save rather than assignment
- 現場で使える Ruby on Rails 5速習実践ガイド (Active Storage を使う際、参考にさせていただきました。)