回答編集履歴

3

解説をさらに補足

2021/02/01 17:38

投稿

oakbow
oakbow

スコア227

test CHANGED
@@ -52,13 +52,13 @@
52
52
 
53
53
  よくある使い方はRails Guideなんかに書いてあるやつですね。
54
54
 
55
- https://railsguides.jp/active_storage_overview.html#file-io-objects%E3%82%92%E3%82%A2%E3%82%BF%E3%83%83%E3%83%81%E3%81%99%E3%82%8B
56
-
57
-
58
-
59
- 例えばすでに保存済みのUserモデルのインスタンス、@userに対して @user.image.attach みたいな使い方を行えます。
60
-
61
- 実際に試した2個目のやり方はこれをやろうとしたんだと思いますが、Drinkモデルのimageは必須になっており、後から画像だけ追加というやり方は今回は使えません。
55
+ [https://railsguides.jp/active_storage_overview.html#file-io-objects%E3%82%92%E3%82%A2%E3%82%BF%E3%83%83%E3%83%81%E3%81%99%E3%82%8B](https://railsguides.jp/active_storage_overview.html#file-io-objects%E3%82%92%E3%82%A2%E3%82%BF%E3%83%83%E3%83%81%E3%81%99%E3%82%8B)
56
+
57
+
58
+
59
+ 例えばすでに保存済みの User モデルのインスタンス、@user に対して @user.image.attach みたいな使い方を行えます。
60
+
61
+ 実際に試した2個目のやり方はこれをやろうとしたんだと思いますが、Drink モデルの image は必須になっており、後から画像だけ追加というやり方は今回は使えません。
62
62
 
63
63
 
64
64
 
@@ -70,9 +70,9 @@
70
70
 
71
71
 
72
72
 
73
- ActiveStorageは active_storage_blobs と active_storage_attachments の二つのテーブルで機能を実現しています。
73
+ ActiveStorageは `active_storage_blobs``active_storage_attachments` の二つのテーブルで機能を実現しています。
74
-
74
+
75
- これはつまり ActiveStorage::Blob と ActiveStorage::Attachment の二つのモデルで構成されていて、今回はその ActiveStorage::Blob を必要としているエラーだと解釈しました。
75
+ これはつまり `ActiveStorage::Blob` と `ActiveStorage::Attachment` の二つのモデルで構成されていて、今回はその `ActiveStorage::Blob` を必要としているエラーだと解釈しました。
76
76
 
77
77
  上の attach メソッドも、中身を見てみると blob を生成しているんですよね。
78
78
 
@@ -110,13 +110,61 @@
110
110
 
111
111
 
112
112
 
113
- create_blob_from がその blob を生成している部分。
114
-
115
- このメソッドは残念なが private メソッドなのでそのまま呼べないんですが、多分 public メソッドで blob を作成すものがあるだろうな探したのが https://edgeapi.rubyonrails.org/classes/ActiveStorage/Blob.html#method-c-create_and_upload-21 って訳です。
116
-
117
-
118
-
119
- >Creates a new blob instance and then uploads the contents of the given io to the service. The blob instance is going to be saved before the upload begins to prevent the upload clobbering another due to key collisions. When providing a content type, pass identify: false to bypass automatic content type inference.
113
+ `create_blob_from` がその blob を生成している部分。
114
+
115
+ この中身をさに追ってみると
116
+
117
+
118
+
119
+ ```
120
+
121
+ def create_blob_from(attachable)
122
+
123
+ case attachable
124
+
125
+ when ActiveStorage::Blob
126
+
127
+ attachable
128
+
129
+ when ActionDispatch::Http::UploadedFile, Rack::Test::UploadedFile
130
+
131
+ ActiveStorage::Blob.create_after_upload! \
132
+
133
+ io: attachable.open,
134
+
135
+ filename: attachable.original_filename,
136
+
137
+ content_type: attachable.content_type
138
+
139
+ when Hash
140
+
141
+ ActiveStorage::Blob.create_after_upload!(attachable)
142
+
143
+ when String
144
+
145
+ ActiveStorage::Blob.find_signed(attachable)
146
+
147
+ else
148
+
149
+ nil
150
+
151
+ end
152
+
153
+ end
154
+
155
+ ```
156
+
157
+ こんな感じ。
158
+
159
+
160
+
161
+ このメソッドは残念ながら private メソッドなのでそのまま呼べないんですが、多分 public メソッドで blob を作成するものがあるだろうなと探したのが [https://edgeapi.rubyonrails.org/classes/ActiveStorage/Blob.html#method-c-create_and_upload-21](https://edgeapi.rubyonrails.org/classes/ActiveStorage/Blob.html#method-c-create_and_upload-21) って訳です。
162
+
163
+ 上のコード内でも出てきてますね。
164
+
165
+
166
+
167
+ > Creates a new blob instance and then uploads the contents of the given io to the service. The blob instance is going to be saved before the upload begins to prevent the upload clobbering another due to key collisions. When providing a content type, pass identify: false to bypass automatic content type inference.
120
168
 
121
169
 
122
170
 
@@ -124,7 +172,9 @@
124
172
 
125
173
 
126
174
 
127
- 実際にこれを使っている実例を探してみたものの見つけられなかったので、残念ながらサンプル的なものは提供できなかったのですが。
175
+ 実際にこれを使っている実例を探してみたものの見つけられなかったので、残念ながらサンプル的なものは提供できなかったのですが。 `attach` メソッド内部でも使われていることと同じことをやる以上、非常に公式な使い方なのでまあ大丈夫だろうなと思いました。
176
+
177
+
128
178
 
129
179
  私はそれほど ActiveStorage 使っていないので少々調べるのに時間がかかりましたが、慣れている人ならもっとスムーズに調べられるかもしれません。
130
180
 
@@ -136,7 +186,7 @@
136
186
 
137
187
  * 使おうとしている機能やライブラリ(ここでは ActiveStorage)の動作の概要を理解する
138
188
 
139
- * RailsGuideなどで紹介されている一般的な利用法で呼び出すメソッドが、Railsやgem内部でどう動いているかを調べる
189
+ * RailsGuideなどで紹介されている一般的な利用法で呼び出すメソッドが、Railsやgem内部でどう動いているかを調べる(この場合は `attach` メソッド)
140
190
 
141
191
 
142
192
 

2

解決に至る思考プロセスを解説

2021/02/01 17:38

投稿

oakbow
oakbow

スコア227

test CHANGED
@@ -37,3 +37,115 @@
37
37
 
38
38
 
39
39
  Rails.root.joinはなくても動く気はしますけれど。
40
+
41
+
42
+
43
+
44
+
45
+ --
46
+
47
+
48
+
49
+ こうすればうまくいくかな?と考えるに至ったプロセスを説明します。
50
+
51
+
52
+
53
+ よくある使い方はRails Guideなんかに書いてあるやつですね。
54
+
55
+ https://railsguides.jp/active_storage_overview.html#file-io-objects%E3%82%92%E3%82%A2%E3%82%BF%E3%83%83%E3%83%81%E3%81%99%E3%82%8B
56
+
57
+
58
+
59
+ 例えばすでに保存済みのUserモデルのインスタンス、@userに対して @user.image.attach みたいな使い方を行えます。
60
+
61
+ 実際に試した2個目のやり方はこれをやろうとしたんだと思いますが、Drinkモデルのimageは必須になっており、後から画像だけ追加というやり方は今回は使えません。
62
+
63
+
64
+
65
+ で、 `ArgumentError: Could not find or build blob: expected attachable,` というエラーメッセージです。
66
+
67
+ 日本語に訳すと「ファイルが見つからないか、またはblobの作成に失敗しました」みたいな感じです。
68
+
69
+ なので、blobデータを必要としているように見えます。
70
+
71
+
72
+
73
+ ActiveStorageは active_storage_blobs と active_storage_attachments の二つのテーブルで機能を実現しています。
74
+
75
+ これはつまり ActiveStorage::Blob と ActiveStorage::Attachment の二つのモデルで構成されていて、今回はその ActiveStorage::Blob を必要としているエラーだと解釈しました。
76
+
77
+ 上の attach メソッドも、中身を見てみると blob を生成しているんですよね。
78
+
79
+
80
+
81
+ ```
82
+
83
+ def attach(attachable)
84
+
85
+ blob_was = blob if attached?
86
+
87
+ blob = create_blob_from(attachable)
88
+
89
+
90
+
91
+ unless blob == blob_was
92
+
93
+ transaction do
94
+
95
+ detach
96
+
97
+ write_attachment build_attachment(blob: blob)
98
+
99
+ end
100
+
101
+
102
+
103
+ blob_was.purge_later if blob_was && dependent == :purge_later
104
+
105
+ end
106
+
107
+ end
108
+
109
+ ```
110
+
111
+
112
+
113
+ create_blob_from がその blob を生成している部分。
114
+
115
+ このメソッドは残念ながら private メソッドなのでそのまま呼べないんですが、多分 public メソッドで blob を作成するものがあるだろうなと探したのが https://edgeapi.rubyonrails.org/classes/ActiveStorage/Blob.html#method-c-create_and_upload-21 って訳です。
116
+
117
+
118
+
119
+ >Creates a new blob instance and then uploads the contents of the given io to the service. The blob instance is going to be saved before the upload begins to prevent the upload clobbering another due to key collisions. When providing a content type, pass identify: false to bypass automatic content type inference.
120
+
121
+
122
+
123
+ って説明を読む限りもそういう目的で使う感じですしね。
124
+
125
+
126
+
127
+ 実際にこれを使っている実例を探してみたものの見つけられなかったので、残念ながらサンプル的なものは提供できなかったのですが。
128
+
129
+ 私はそれほど ActiveStorage 使っていないので少々調べるのに時間がかかりましたが、慣れている人ならもっとスムーズに調べられるかもしれません。
130
+
131
+ コツとしては
132
+
133
+
134
+
135
+ * エラーメッセージを読む(言語やフレームワークがうまくいかない理由を教えてくれているので、一番のヒント)
136
+
137
+ * 使おうとしている機能やライブラリ(ここでは ActiveStorage)の動作の概要を理解する
138
+
139
+ * RailsGuideなどで紹介されている一般的な利用法で呼び出すメソッドが、Railsやgem内部でどう動いているかを調べる
140
+
141
+
142
+
143
+ というところかなと思います。
144
+
145
+ でも、これを解決できるのは個人的な感覚では中級者以上で、ちょっと難しいかな、という気はします。
146
+
147
+
148
+
149
+ 実際にはそこまで調べずに解決できないかなーと、seed 側でこの手の問題を解決した情報がないかとか探してみたんですが、まあたいていはあとから attach する RailsGuide のパターンでやっている例ばかりでした。
150
+
151
+ そのものズバリの例をどこかで見つけられると上の三つのステップなんていらないんですが、まあそういつも楽できるとは限りません。

1

回答の間違いを修正

2021/02/01 17:07

投稿

oakbow
oakbow

スコア227

test CHANGED
@@ -1,4 +1,4 @@
1
- 一番最初のパターンで、
1
+ ~~一番最初のパターンで、~~
2
2
 
3
3
 
4
4
 
@@ -10,4 +10,30 @@
10
10
 
11
11
 
12
12
 
13
- とやってもうまくいかないでしょうか。
13
+ ~~とやってもうまくいかないでしょうか。
14
+
15
+ ~~
16
+
17
+
18
+
19
+ 完全に読み違えていました。
20
+
21
+ Drinkのimageが必須になっているのでこれが任意にできるのなら簡単なんですけれど。
22
+
23
+
24
+
25
+ 手元で試せないのでうまくいくか未確認ですが、[ActiveStorage::Blob.create_and_upload! ](https://edgeapi.rubyonrails.org/classes/ActiveStorage/Blob.html#method-c-create_and_upload-21)を使ってみるとどうなるでしょうか。
26
+
27
+ 最初のパターンでこう書きます。
28
+
29
+
30
+
31
+ ```
32
+
33
+ iamge: ActiveStorage::Blob.create_and_upload!(io: File.open(Rails.root.join("app/assets/images/houseblend.jpeg"))
34
+
35
+ ```
36
+
37
+
38
+
39
+ Rails.root.joinはなくても動く気はしますけれど。