2
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

refile seedデータでの画像登録方法と仕組み🤔💭

Last updated at Posted at 2021-05-19

ある日、『refileで扱う画像をseedデータで設定するにはどうすればいいのですか?』という質問を受けたので調べながら答えたのをこの記事にまとめようと思いました。

設定方法だけでなく、軽く仕組みも調査してみました。

gem refile のgithubはこちら ↓

先ずは設定方法の結論から 🤑

例えば、公式githubのコードを参考にして説明すると...

usersテーブルのカラムに profile_image_id というものが存在するとします。

その場合は、Userモデルで例えると以下のようになります。

app/models/user.rb
class User < ActiveRecord::Base
  # _id は書かないのがポイント
  attachment :profile_image
end

app/assets/images/ ディレクトリ以下に任意の画像を置く

今回は smile.jpg というものが存在する前提で話を進めます。

seeds.rbでuserを作成する際にある画像を設定する

db/seeds.rb
# この時、_id を書かないのがポイント
User.create(
  任意のカラム名など: 任意の値,
  ...,
  profile_image: File.open("./app/assets/images/smile.jpg")
)
$ rails db:seed

これで、画像の設定が完成しています!

だが しか~~~しっ !、!!

Ruby on Rails をよく分かっている方は違和感を持つことでしょう。
なぜ profile_image が create の引数にあるのか。。。
DBのカラム名に相当するprofile_image_id ではないのか。。。

より深く仕組みを知りたい方は続きを読んでみてください。

そもそもrefileの仕組み ~ 公式のREADMEを読んでみる🧐📕

Files are uploaded to a backend. The backend assigns an ID to this file, which will be unique for this file within the backend.

ファイルがuploadされたら、fileにuniqueなidを割り当てる。

By default files will be uploaded to ./tmp/uploads/store

デフォルトではuploadされたファイルはコンパイルか何かされてファイル名がそのuniqueなidになっており、 ./tmp/uplaods/store に保存される。(ここではstoreと呼びます。)

画像を復元する場合、uniqueなidを元にstoreから画像を復元する仕組みのようです。

Attachments の部分

class User < ActiveRecord::Base
  attachment :profile_image
end

Calling attachment generates a getter and setter with the given name. When you assign a file to the setter, it is uploaded to the cache:

attachment の引数の名前が getter setterのメソッドになるようです。

今回の例でいうと、
user.profile_image で何かしら値を取得したり、
user.profile_image= で値を設定できるということです。

ちなみに、ActiveRecordの仕様として
setterメソッドxxx=は、モデル名.new(xxx: 任意の値)で設定できるようになっています。(気が向いたらブログかqiitaで詳しく書きます。)

つまり、 以下のコードは同じ結果になるということです。

# インスタンス生成後にsetするパターン。
user = User.new
user.name = 'Refile太郎'
user.name # => Refile太郎
user.save

# ----------------------------------

# インスタンス生成時の引数に値を指定するパターン。
user = User.new(name: 'Refile太郎')
user.name # => Refile太郎
user.save

createメソッドは実はnewメソッドとsaveメソッドを実行してオブジェクトを返却するものです。
以下ソースコード (https://github.com/rails/rails/blob/main/activerecord/lib/active_record/persistence.rb#L33-L41)

なので冒頭の createの引数に なぜ profile_image: 値 が create の引数にある場合、newの引数に profile_image: 値 が渡っていき最終的にsaveされます。

しかし、 profile_image_id カラムに画像idが保存される仕組みは謎です🤔💭

続いてrefile公式のREADMEから一部コードと説明の抜粋して仕組み追っていきます。

User.new
# 公式では↑のように書いているが
# user = User.new と解釈しておきましょう。

File.open("/some/path", "rb") do |file|
  user.profile_image = file # fileオブジェクトをsetしている。
end

# profile_image.id とすると画像idが取得できる。
user.profile_image.id # => "fec421..." 

When you call save on the record, the uploaded file is transferred from the cache to the store.

cacheは一時的なファイルデータ(DBなどの永続ストレージに保存されていない状態。)
storeはDBなどの永続ストレージと判断して良さそうです。
storeは永続的なストレージですが、デフォルトで画像fileが保存される ./tmp/uploads/store のことでした。

説明文を解釈するとuser.profile_image にfileオブジェクトをセットした後に user.save すると、画像ファイルが./tmp/uploads/storeに保存される。

もしかして、この時についでにDBのusersテーブルのprofile_image_idカラムに画像idが保存されるんじゃね?!(◎_◎;)

実際に検証してみましょう。
スクリーンショット 2021-05-20 1.31.11.png
save前はprofile_image_idnilですが、save後は、
profile_image_idに画像idが入っていました!
(実際にrefileのコードを見るとsave前にそうする仕組みになっていました。気が向いたらそのことの書きます。。。)

これで、 しかし、 profile_image_id カラムに画像idが保存される仕組みは謎です🤔💭 の謎は解けました。

別の書き方でseedデータを作成するなら🧐💭(全くこの方法で書く必要性はないのですが)

先ほど最後の行で画像idを取得できていました。

# profile_image.id とすると画像idが取得できる。
user.profile_image.id # => "fec421..." 

なので user.profile_image_id = 画像id をした後にsaveしても画像idの保存は可能です。
例えば以下のような書き方でもseedデータを作成できます。

db/seeds.rb
user = User.create(
  任意のカラム名など: 任意の値,
  ...
)

File.open("./app/assets/images/smile.jpg") do |file|
  user.profile_image = file
end 
# ちなみに、上記の記述はこのように書くことも可能です。
# user.profile_image = File.open("./app/assets/images/smile.jpg")

# 画像idをuser.profile_image_idにsetします。
# しかし以下の記述はなくてよい。
user.profile_image_id = user.profile_image.id

user.save
rails db:seed

まとめ😌

  • モデルに定義した attachment :xxx によってfileオブジェクトを格納できる xxx という getter, setterメソッドが利用可能になる。

  • fileオブジェクトがsetされているならば、 xxx.id で画像idが取得できる。

  • fileオブジェクトがsetされている状態でsaveすると xxx_id カラムに画像idが保存される。

この仕組みをrefileのソースコードを追いながら調査した記事も自分のブログかqiitaで近日公開しようかと思います。(気が向いたら...)

2
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?