refileの使い方徹底解説②
前回は基本的なrefileの使い方を見ていきました。
今回は画像がどこに保存されるのかを調べていきます。
まずはviewから画像を保存できるようにします。
/books/new にアクセスします。
ここからまずタイトルと画像を保存できるようにします。
# _form.html.erb
<%= form_with(model: book, local: true) do |form| %>
# 省略
<%= form.text_field :title %>
<%= form.attachment_field :main_image %>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
refileでは画像をアップロードするために attachment_field というhelperが提供されているのでこれを使用します。
こんな感じになります。
適当に値を入力してみます。
保存します。
保存できたようです。一応、ログを確認してみます。
Started POST "/books" for ::1 at 2020-07-31 17:55:04 +0900
Processing by BooksController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"I+UxMoDJEwSHiEBdJ3l/YgYjQtMlCyXRI0GpTYoIM9DK5CCEl+dhHv/RG958N3xT4EHiQcK08qDYW9MpYLx+Ig==", "book"=>{"title"=>"テスト1", "main_image"=>#<ActionDispatch::Http::UploadedFile:0x00007f977a1cf868 @tempfile=#<Tempfile:/var/folders/qz/rvvc7fwn75x4dyv2tk72q2600000gn/T/RackMultipart20200731-27990-hte399.png>, @original_filename="rails_logo.png", @content_type="image/png", @headers="Content-Disposition: form-data; name=\"book[main_image]\"; filename=\"rails_logo.png\"\r\nContent-Type: image/png\r\n">}, "commit"=>"Create Book"}
(0.1ms) begin transaction
↳ app/controllers/books_controller.rb:30
Book Create (2.2ms) INSERT INTO "books" ("title", "main_image_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["title", "テスト1"], ["main_image_id", "c701185ec9d93759c5c64c93078ca7343f4f501422420d3ddec64b1583eb"], ["created_at", "2020-07-31 08:55:04.808779"], ["updated_at", "2020-07-31 08:55:04.808779"]]
↳ app/controllers/books_controller.rb:30
(0.8ms) commit transaction
↳ app/controllers/books_controller.rb:30
Redirected to http://localhost:3000/books/2
Completed 302 Found in 13ms (ActiveRecord: 3.1ms)
ログをみても保存処理が成功していることがわかりました。
今度はviewに保存した画像を表示してみます。
# show.html.erb
<p id="notice"><%= notice %></p>
<%= attachment_image_tag(@book, :main_image, :fill, 300, 300) %>
<%= link_to 'Edit', edit_book_path(@book) %> |
<%= link_to 'Back', books_path %>
画像を表示するには attachment_image_tag を使います。bookのshowページにアクセスしてみます。
エラーが表示されました。エラー文を読んでみると
Refile.secret_key was not set.
Please add the following to your Refile configuration and restart your application:
となっているので表示されている secret_key を設定します。
config/initializers/application_controller_renderer.rb にエラーメッセージに表示されている secret_key を 記述します。
# application_controller_renderer.rb
# xxxはエラーメッセージに表示されているsecret_keyを記述する
Refile.secret_key = 'xxx'
そしてrailsを再起動します。
~/w/r/refile_app ❯❯❯ rails s
再度bookのshowページにアクセスしてみると
画像が表示されていることを確認できました。
今度はこの画像はどこに保存されているのか確認してみます。
rails cでbooksテーブルのデータを見てみます。
~/w/r/refile_app ❯❯❯ rails c master ◼
BRunning via Spring preloader in process 32676
Loading development environment (Rails 5.2.4.3)
irb(main):001:0> Book.first
Book Load (0.4ms) SELECT "books".* FROM "books" ORDER BY "books"."id" ASC LIMIT ? [["LIMIT", 1]]
=> #<Book id: 1, title: nil, main_image_id: "1bae063ba8442393dd62a7fdac3d4a6a8d82ab6d76cd83d8bc...", created_at: "2020-07-31 08:26:35", updated_at: "2020-07-31 08:26:35">
画像を保存しているのは main_image_id というカラムなのでこのメソッドを呼び出してみます。
irb(main):002:0> Book.last.main_image_id
Book Load (0.2ms) SELECT "books".* FROM "books" ORDER BY "books"."id" ASC LIMIT ? [["LIMIT", 1]]
=> "c701185ec9d93759c5c64c93078ca7343f4f501422420d3ddec64b1583eb"
こいつの正体は何なのかを調べてみます。まずはこのデータがどのclassに属しているのかを確認してみます。
irb(main):003:0> Book.last.main_image_id.class
Book Load (0.1ms) SELECT "books".* FROM "books" ORDER BY "books"."id" ASC LIMIT ? [["LIMIT", 1]]
=> String
booksテーブルのmain_image_idカラムはstring型に設定したので当たり前だがstring class と表示されます。
これだけを見てみてもよくわからないのでもう一度showページを開いてみます。
chromeの検証モードで画像を確認してみます。
表示されるHTMLのタグのsrcに
/attachments/8d205ec96253ec2bbf4324caea1a41dd02268d07/store/fill/300/300/c701185ec9d93759c5c64c93078ca7343f4f501422420d3ddec64b1583eb/main_image
と表示されていました。どうやらbooksテーブルのmain_image_idに保存されている値は c701185ec9d93759c5c64c93078ca7343f4f501422420d3ddec64b1583eb の部分を表しているようです。
プログラムの動きやデータのみではよくわからなかったのでGem refileのGithubを確認してみます。
By default files will be uploaded to ./tmp/uploads/store.
と書かれており、どうやら tmp ディレクトリ以下に実際のファイルがアップロードされているとのことです。確認してみます。
~/w/r/refile_app ❯❯❯ ls tmp/uploads/store master ◼
c701185ec9d93759c5c64c93078ca7343f4f501422420d3ddec64b1583eb
irb(main):002:0> Book.last.main_image_id
Book Load (0.2ms) SELECT "books".* FROM "books" ORDER BY "books"."id" ASC LIMIT ? [["LIMIT", 1]]
=> "c701185ec9d93759c5c64c93078ca7343f4f501422420d3ddec64b1583eb"
確かにrails cで確認した最後に登録した画像と同じidのファイルが tmp/uploads/store 以下に保存されていました。
どうやら main_image_id カラムに保存するデータは、ファイルにランダムな値を割り振ってidとして管理し、そのidのファイルがtmp/uploads/store 以下のどのファイルかを判定するための識別子のようでした。
これで画像を保存する一連の流れ、どこに保存されるのかということが理解できました。
次回は複数枚画像を保存する方法を見ていきます。