質問編集履歴

3

内容訂正

2017/02/17 08:10

投稿

besuko
besuko

スコア16

test CHANGED
@@ -1 +1 @@
1
- 【Rails】Dropzonejsでデータを保存するタイミングの変更方法
1
+ 【Rails】画像データをドラッグ&ドロップでアップする方法
test CHANGED
@@ -1,3 +1,37 @@
1
+ ######ドラッグ&ドロップでのファイルアップロードに苦戦しています。
2
+
3
+
4
+
5
+
6
+
7
+ ファイルのアップロードはgem'Dropzonejs'を使っています。
8
+
9
+
10
+
11
+ 店舗を検索するサイトを作っており、住所等の店舗情報を入力するフォーム内に、同時に画像データも保存させるようにしたいと考えております。
12
+
13
+
14
+
15
+ ただ残念ながらDropzonejsはデフォルトではデータをドラッグしたタイミングに保存されるようになっています。
16
+
17
+ そのため、shop.newの時点でshop_idを持たないimageをそのまま保存することが出来ない状況です。
18
+
19
+
20
+
21
+ 現状、shopをcreate後、shoop_idを用いて@shop.images.buildしてnewページを出していますが、店舗情報と画像登録画面が別になっておりスマートな方法ではありません。
22
+
23
+ これをドラッグしたタイミング→データの保持、保存ボタンを押したタイミング→データを保存というように変更したいと考えています。
24
+
25
+
26
+
27
+ ①Dropzonejsのjsファイルをカスタマイズする
28
+
29
+ ②Dropzonejsは使わずに、独自でドラッグ&ドロップフォームを作る
30
+
31
+ のいずれかが解決方法となるかと思います。
32
+
33
+ グーグルで検索しても目ぼしい情報が得られずにいますので、ご教示頂けますと幸いです。
34
+
1
35
  ###環境
2
36
 
3
37
  Ruby2.3.3
@@ -10,410 +44,176 @@
10
44
 
11
45
  gem 'dropzonejs-rails'
12
46
 
13
-
14
-
15
- ###問題
16
-
17
- Railsのファイルのアップロードでgem'Dropzonejs'を使っています。
18
-
19
- 店舗を検索するサイトを作っており、店舗名や住所ータと同時に画像データも保存させるようにしたいと考えております。
20
-
21
- なお、店舗モデル(shop)と画像モデル(shop_image)を分けており、リレーションは「shop has_many shop_images」としています。
22
-
23
-
24
-
25
- 残念ながらDropzonejsはデフォルトではデータをドラッグしたタイミングに保存されるようになっています。
26
-
27
- そのため、shop_idを持たないshop_imageをそのまま保存することが出来ない状況です。
28
-
29
- これをドラッグしたタイミング→ータの保持、保存ボタンを押したタイミング→データを保存というように変更したいと考えています。
30
-
31
-
32
-
33
- 以下JSファイルのどこかを編集すれば良いのだと思いますが、当方JSの知識がほぼゼロでございます。。
34
-
35
- グーグルで検索しても目ぼしい情報が得られずにいますので、ご教示頂けますと幸いです。
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
- ###恐らく編集すべきファイル「dropzone.js」のこの部分であろう一部を抜粋
44
-
45
- ```JavaScript
46
-
47
- Dropzone.prototype.defaultOptions = {
48
-
49
- url: null,
50
-
51
- method: "post",
52
-
53
- withCredentials: false,
54
-
55
- parallelUploads: 2,
56
-
57
- uploadMultiple: false,
58
-
59
- maxFilesize: 256,
60
-
61
- paramName: "file",
62
-
63
- createImageThumbnails: true,
64
-
65
- maxThumbnailFilesize: 10,
66
-
67
- thumbnailWidth: 120,
68
-
69
- thumbnailHeight: 120,
70
-
71
- filesizeBase: 1000,
72
-
73
- maxFiles: null,
74
-
75
- params: {},
76
-
77
- clickable: true,
78
-
79
- ignoreHiddenFiles: true,
80
-
81
- acceptedFiles: null,
82
-
83
- acceptedMimeTypes: null,
84
-
85
- autoProcessQueue: true,
86
-
87
- autoQueue: true,
88
-
89
- addRemoveLinks: false,
90
-
91
- previewsContainer: null,
92
-
93
- hiddenInputContainer: "body",
94
-
95
- capture: null,
96
-
97
- renameFilename: null,
98
-
99
- dictDefaultMessage: "Drop files here to upload",
100
-
101
- dictFallbackMessage: "Your browser does not support drag'n'drop file uploads.",
102
-
103
- dictFallbackText: "Please use the fallback form below to upload your files like in the olden days.",
104
-
105
- dictFileTooBig: "File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.",
106
-
107
- dictInvalidFileType: "You can't upload files of this type.",
108
-
109
- dictResponseError: "Server responded with {{statusCode}} code.",
110
-
111
- dictCancelUpload: "Cancel upload",
112
-
113
- dictCancelUploadConfirmation: "Are you sure you want to cancel this upload?",
114
-
115
- dictRemoveFile: "Remove file",
116
-
117
- dictRemoveFileConfirmation: null,
118
-
119
- dictMaxFilesExceeded: "You can not upload any more files.",
120
-
121
- accept: function(file, done) {
122
-
123
- return done();
124
-
125
- },
126
-
127
- init: function() {
128
-
129
- return noop;
130
-
131
- },
132
-
133
- forceFallback: false,
134
-
135
- fallback: function() {
136
-
137
- var child, messageElement, span, _i, _len, _ref;
138
-
139
- this.element.className = "" + this.element.className + " dz-browser-not-supported";
140
-
141
- _ref = this.element.getElementsByTagName("div");
142
-
143
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
144
-
145
- child = _ref[_i];
146
-
147
- if (/(^| )dz-message($| )/.test(child.className)) {
148
-
149
- messageElement = child;
150
-
151
- child.className = "dz-message";
152
-
153
- continue;
154
-
155
- }
156
-
157
- }
158
-
159
- if (!messageElement) {
160
-
161
- messageElement = Dropzone.createElement("<div class=\"dz-message\"><span></span></div>");
162
-
163
- this.element.appendChild(messageElement);
164
-
165
- }
166
-
167
- span = messageElement.getElementsByTagName("span")[0];
168
-
169
- if (span) {
170
-
171
- if (span.textContent != null) {
172
-
173
- span.textContent = this.options.dictFallbackMessage;
174
-
175
- } else if (span.innerText != null) {
176
-
177
- span.innerText = this.options.dictFallbackMessage;
178
-
179
- }
180
-
181
- }
182
-
183
- return this.element.appendChild(this.getFallbackForm());
184
-
185
- },
186
-
187
- resize: function(file) {
188
-
189
- var info, srcRatio, trgRatio;
190
-
191
- info = {
192
-
193
- srcX: 0,
194
-
195
- srcY: 0,
196
-
197
- srcWidth: file.width,
198
-
199
- srcHeight: file.height
200
-
201
- };
202
-
203
- srcRatio = file.width / file.height;
204
-
205
- info.optWidth = this.options.thumbnailWidth;
206
-
207
- info.optHeight = this.options.thumbnailHeight;
208
-
209
- if ((info.optWidth == null) && (info.optHeight == null)) {
210
-
211
- info.optWidth = info.srcWidth;
212
-
213
- info.optHeight = info.srcHeight;
214
-
215
- } else if (info.optWidth == null) {
216
-
217
- info.optWidth = srcRatio * info.optHeight;
218
-
219
- } else if (info.optHeight == null) {
220
-
221
- info.optHeight = (1 / srcRatio) * info.optWidth;
222
-
223
- }
224
-
225
- trgRatio = info.optWidth / info.optHeight;
226
-
227
- if (file.height < info.optHeight || file.width < info.optWidth) {
228
-
229
- info.trgHeight = info.srcHeight;
230
-
231
- info.trgWidth = info.srcWidth;
232
-
233
- } else {
234
-
235
- if (srcRatio > trgRatio) {
236
-
237
- info.srcHeight = file.height;
238
-
239
- info.srcWidth = info.srcHeight * trgRatio;
240
-
241
- } else {
242
-
243
- info.srcWidth = file.width;
244
-
245
- info.srcHeight = info.srcWidth / trgRatio;
246
-
247
- }
248
-
249
- }
250
-
251
- info.srcX = (file.width - info.srcWidth) / 2;
252
-
253
- info.srcY = (file.height - info.srcHeight) / 2;
254
-
255
- return info;
256
-
257
- },
258
-
259
-
260
-
261
- /*
262
-
263
- Those functions register themselves to the events on init and handle all
264
-
265
- the user interface specific stuff. Overwriting them won't break the upload
266
-
267
- but can break the way it's displayed.
268
-
269
- You can overwrite them if you don't like the default behavior. If you just
270
-
271
- want to add an additional event handler, register it on the dropzone object
272
-
273
- and don't overwrite those options.
274
-
275
- */
276
-
277
- drop: function(e) {
278
-
279
- return this.element.classList.remove("dz-drag-hover");
280
-
281
- },
282
-
283
- dragstart: noop,
284
-
285
- dragend: function(e) {
286
-
287
- return this.element.classList.remove("dz-drag-hover");
288
-
289
- },
290
-
291
- dragenter: function(e) {
292
-
293
- return this.element.classList.add("dz-drag-hover");
294
-
295
- },
296
-
297
- dragover: function(e) {
298
-
299
- return this.element.classList.add("dz-drag-hover");
300
-
301
- },
302
-
303
- dragleave: function(e) {
304
-
305
- return this.element.classList.remove("dz-drag-hover");
306
-
307
- },
308
-
309
- paste: noop,
310
-
311
- reset: function() {
312
-
313
- return this.element.classList.remove("dz-started");
314
-
315
- },
316
-
317
- addedfile: function(file) {
318
-
319
- var node, removeFileEvent, removeLink, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _results;
320
-
321
- if (this.element === this.previewsContainer) {
322
-
323
- this.element.classList.add("dz-started");
324
-
325
- }
326
-
327
- if (this.previewsContainer) {
328
-
329
- file.previewElement = Dropzone.createElement(this.options.previewTemplate.trim());
330
-
331
- file.previewTemplate = file.previewElement;
332
-
333
- this.previewsContainer.appendChild(file.previewElement);
334
-
335
- _ref = file.previewElement.querySelectorAll("[data-dz-name]");
336
-
337
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
338
-
339
- node = _ref[_i];
340
-
341
- node.textContent = this._renameFilename(file.name);
342
-
343
- }
344
-
345
- _ref1 = file.previewElement.querySelectorAll("[data-dz-size]");
346
-
347
- for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
348
-
349
- node = _ref1[_j];
350
-
351
- node.innerHTML = this.filesize(file.size);
352
-
353
- }
354
-
355
- if (this.options.addRemoveLinks) {
356
-
357
- file._removeLink = Dropzone.createElement("<a class=\"dz-remove\" href=\"javascript:undefined;\" data-dz-remove>" + this.options.dictRemoveFile + "</a>");
358
-
359
- file.previewElement.appendChild(file._removeLink);
360
-
361
- }
362
-
363
- removeFileEvent = (function(_this) {
364
-
365
- return function(e) {
366
-
367
- e.preventDefault();
368
-
369
- e.stopPropagation();
370
-
371
- if (file.status === Dropzone.UPLOADING) {
372
-
373
- return Dropzone.confirm(_this.options.dictCancelUploadConfirmation, function() {
374
-
375
- return _this.removeFile(file);
376
-
377
- });
378
-
379
- } else {
380
-
381
- if (_this.options.dictRemoveFileConfirmation) {
382
-
383
- return Dropzone.confirm(_this.options.dictRemoveFileConfirmation, function() {
384
-
385
- return _this.removeFile(file);
386
-
387
- });
388
-
389
- } else {
390
-
391
- return _this.removeFile(file);
392
-
393
- }
394
-
395
- }
396
-
397
- };
398
-
399
- })(this);
400
-
401
- _ref2 = file.previewElement.querySelectorAll("[data-dz-remove]");
402
-
403
- _results = [];
404
-
405
- for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
406
-
407
- removeLink = _ref2[_k];
408
-
409
- _results.push(removeLink.addEventListener("click", removeFileEvent));
410
-
411
- }
412
-
413
- return _results;
414
-
415
- }
416
-
417
- },
418
-
419
- ```
47
+ ###モデル
48
+
49
+ Shop→imageをネストしています。
50
+
51
+
52
+
53
+ shop(店舗)モ
54
+
55
+ |id|name|address||
56
+
57
+ |:--:|:--:|:--:|
58
+
59
+ |1|店舗名|住所|
60
+
61
+
62
+
63
+ image(画像)モ
64
+
65
+ |id|shop_id|file|
66
+
67
+ |:--:|:--:|:--:|
68
+
69
+ |1|1|file|
70
+
71
+
72
+
73
+ ###該当箇所のコード
74
+
75
+ routes.rb
76
+
77
+ ```ruby
78
+
79
+ resources :shops, only: [:show] do
80
+
81
+ resources :images, only: [:new, :create, :destroy] do
82
+
83
+ collection do
84
+
85
+ post :upload
86
+
87
+ end
88
+
89
+ end
90
+
91
+ end
92
+
93
+ ```
94
+
95
+
96
+
97
+ shop.rb
98
+
99
+ ```ruby
100
+
101
+ class Shop < ApplicationRecord
102
+
103
+ has_many :images, dependent: :destroy
104
+
105
+ end
106
+
107
+ ```
108
+
109
+
110
+
111
+ image.rb
112
+
113
+ ```ruby
114
+
115
+ class ShopImage < ApplicationRecord
116
+
117
+ belongs_to :shop, optional: true
118
+
119
+ mount_uploader :file, ImageUploader
120
+
121
+ end
122
+
123
+ ```
124
+
125
+
126
+
127
+ shops_controller.rb
128
+
129
+ ```ruby
130
+
131
+ def create
132
+
133
+ @shop = current_user.shops.build(shop_params)
134
+
135
+ respond_to do |format|
136
+
137
+ if verify_recaptcha(model: @shop) && @shop.save
138
+
139
+ format.html { redirect_to "/shops/#{@shop.id}/images/new", notice: '画像を登録してください。' }
140
+
141
+ format.json { render :show, status: :created, location: @shop }
142
+
143
+ else
144
+
145
+ format.html { render :new }
146
+
147
+ format.json { render json: @shop.errors, status: :unprocessable_entity }
148
+
149
+ end
150
+
151
+ end
152
+
153
+ end
154
+
155
+ ```
156
+
157
+
158
+
159
+ image_controller.rb
160
+
161
+ ```ruby
162
+
163
+ def upload
164
+
165
+ @shop = Shop.find(params[:shop_id])
166
+
167
+ image = @shop.images.build(file: params['file'])
168
+
169
+ image.save!
170
+
171
+ render status: 200, json: @shop.images
172
+
173
+ end
174
+
175
+ ```
176
+
177
+
178
+
179
+ images/new.html.erb
180
+
181
+ ```
182
+
183
+ <h1>画像の登録</h1>
184
+
185
+
186
+
187
+ <%= render 'form' %>
188
+
189
+
190
+
191
+ <% @shop.images.each do |image| %>
192
+
193
+ <div id="image_<%=image.id%>">
194
+
195
+ <%= image_tag(image.file.url, :width => '200px') %>
196
+
197
+ <%= link_to content_tag(:i, '', class: 'fa fa-trash'), image_path(@shop, image), method: :delete, data: { confirm: "本当に削除してもよろしいですか" }, class: "image_delete", remote: true %>
198
+
199
+ </div>
200
+
201
+ <% end %>
202
+
203
+ ```
204
+
205
+
206
+
207
+ images/_form.html.erb
208
+
209
+ ```html
210
+
211
+ <div class="fallback">
212
+
213
+ <%= form_tag(upload_shop_images_path(@shop, remote: true),
214
+
215
+ :id => 'upload-dropzone', :class => 'dropzone', method: :post) %>
216
+
217
+ </div>
218
+
219
+ ```

2

モデルのリレーションについて追加

2017/02/17 08:10

投稿

besuko
besuko

スコア16

test CHANGED
File without changes
test CHANGED
@@ -16,9 +16,15 @@
16
16
 
17
17
  Railsのファイルのアップロードでgem'Dropzonejs'を使っています。
18
18
 
19
- フォーム内で他のデータと同じタイミングで画像データ保存できるようにしたいす。
19
+ 店舗を検索するサイトを作っており、店舗名や住所データと同時に画像データ保存させるようにしたいと考えております。
20
+
20
-
21
+ なお、店舗モデル(shop)と画像モデル(shop_image)を分けており、リレーションは「shop has_many shop_images」としています。
22
+
23
+
24
+
21
- お、デフォルトではデータをドラッグしたタイミング保存されるようになっています。
25
+ 残念がらDropzonejsはデフォルトではデータをドラッグしたタイミング保存されるようになっています。
26
+
27
+ そのため、shop_idを持たないshop_imageをそのまま保存することが出来ない状況です。
22
28
 
23
29
  これをドラッグしたタイミング→データの保持、保存ボタンを押したタイミング→データを保存というように変更したいと考えています。
24
30
 

1

誤字を訂正しました。

2017/02/17 03:50

投稿

besuko
besuko

スコア16

test CHANGED
@@ -1 +1 @@
1
- 【Rails】Dropzone.jsでアップロドができない
1
+ 【Rails】Dropzonejsでタを保存するタイミングの変更方法
test CHANGED
@@ -1,309 +1,413 @@
1
- RailsでDropzone.js という JavaScript ライブラリを用いて、ドラッグ&ドロップによるファイルアップロード機能の実装を試みています。
2
-
3
-
4
-
5
- 親モデルの「Shop」にネストされたファイル保存用の子モデル「Attachment」の「image」カラムにアップロードすることが目標です。
6
-
7
-
8
-
9
- 現状、ファイルをドラッグしてプレビューを表示するところまで出来ました。
10
-
11
- そこからドラッグした時点で親モデルが一つCreateされ、ファイルはアップロードされていない状況です。
12
-
13
-
14
-
15
- Shopをnew→createした時にコンソールには
1
+ ###環境
2
+
3
+ Ruby2.3.3
4
+
5
+ Rails5.0.1
6
+
7
+
8
+
9
+ ###Gem
10
+
11
+ gem 'dropzonejs-rails'
12
+
13
+
14
+
15
+ ###問題
16
+
17
+ Railsのファイルのアップロードでgem'Dropzonejs'を使っています。
18
+
19
+ フォーム内で他のデータと同じタイミングで画像データを保存できるようにしたいです。
20
+
21
+ なお、デフォルトではデータをドラッグしたタイミング→保存されるようになっています。
22
+
23
+ これをドラッグしたタイミング→データの保持、保存ボタンを押したタイミング→データを保存というように変更したいと考えています。
24
+
25
+
26
+
27
+ 以下JSファイルのどこかを編集すれば良いのだと思いますが、当方JSの知識がほぼゼロでございます。。
28
+
29
+ グーグルで検索しても目ぼしい情報が得られずにいますので、ご教示頂けますと幸いです。
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+ ###恐らく編集すべきファイル「dropzone.js」のこの部分であろう一部を抜粋
38
+
39
+ ```JavaScript
40
+
41
+ Dropzone.prototype.defaultOptions = {
42
+
43
+ url: null,
44
+
45
+ method: "post",
46
+
47
+ withCredentials: false,
48
+
49
+ parallelUploads: 2,
50
+
51
+ uploadMultiple: false,
52
+
53
+ maxFilesize: 256,
54
+
55
+ paramName: "file",
56
+
57
+ createImageThumbnails: true,
58
+
59
+ maxThumbnailFilesize: 10,
60
+
61
+ thumbnailWidth: 120,
62
+
63
+ thumbnailHeight: 120,
64
+
65
+ filesizeBase: 1000,
66
+
67
+ maxFiles: null,
68
+
69
+ params: {},
70
+
71
+ clickable: true,
72
+
73
+ ignoreHiddenFiles: true,
74
+
75
+ acceptedFiles: null,
76
+
77
+ acceptedMimeTypes: null,
78
+
79
+ autoProcessQueue: true,
80
+
81
+ autoQueue: true,
82
+
83
+ addRemoveLinks: false,
84
+
85
+ previewsContainer: null,
86
+
87
+ hiddenInputContainer: "body",
88
+
89
+ capture: null,
90
+
91
+ renameFilename: null,
92
+
93
+ dictDefaultMessage: "Drop files here to upload",
94
+
95
+ dictFallbackMessage: "Your browser does not support drag'n'drop file uploads.",
96
+
97
+ dictFallbackText: "Please use the fallback form below to upload your files like in the olden days.",
98
+
99
+ dictFileTooBig: "File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.",
100
+
101
+ dictInvalidFileType: "You can't upload files of this type.",
102
+
103
+ dictResponseError: "Server responded with {{statusCode}} code.",
104
+
105
+ dictCancelUpload: "Cancel upload",
106
+
107
+ dictCancelUploadConfirmation: "Are you sure you want to cancel this upload?",
108
+
109
+ dictRemoveFile: "Remove file",
110
+
111
+ dictRemoveFileConfirmation: null,
112
+
113
+ dictMaxFilesExceeded: "You can not upload any more files.",
114
+
115
+ accept: function(file, done) {
116
+
117
+ return done();
118
+
119
+ },
120
+
121
+ init: function() {
122
+
123
+ return noop;
124
+
125
+ },
126
+
127
+ forceFallback: false,
128
+
129
+ fallback: function() {
130
+
131
+ var child, messageElement, span, _i, _len, _ref;
132
+
133
+ this.element.className = "" + this.element.className + " dz-browser-not-supported";
134
+
135
+ _ref = this.element.getElementsByTagName("div");
136
+
137
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
138
+
139
+ child = _ref[_i];
140
+
141
+ if (/(^| )dz-message($| )/.test(child.className)) {
142
+
143
+ messageElement = child;
144
+
145
+ child.className = "dz-message";
146
+
147
+ continue;
148
+
149
+ }
150
+
151
+ }
152
+
153
+ if (!messageElement) {
154
+
155
+ messageElement = Dropzone.createElement("<div class=\"dz-message\"><span></span></div>");
156
+
157
+ this.element.appendChild(messageElement);
158
+
159
+ }
160
+
161
+ span = messageElement.getElementsByTagName("span")[0];
162
+
163
+ if (span) {
164
+
165
+ if (span.textContent != null) {
166
+
167
+ span.textContent = this.options.dictFallbackMessage;
168
+
169
+ } else if (span.innerText != null) {
170
+
171
+ span.innerText = this.options.dictFallbackMessage;
172
+
173
+ }
174
+
175
+ }
176
+
177
+ return this.element.appendChild(this.getFallbackForm());
178
+
179
+ },
180
+
181
+ resize: function(file) {
182
+
183
+ var info, srcRatio, trgRatio;
184
+
185
+ info = {
186
+
187
+ srcX: 0,
188
+
189
+ srcY: 0,
190
+
191
+ srcWidth: file.width,
192
+
193
+ srcHeight: file.height
194
+
195
+ };
196
+
197
+ srcRatio = file.width / file.height;
198
+
199
+ info.optWidth = this.options.thumbnailWidth;
200
+
201
+ info.optHeight = this.options.thumbnailHeight;
202
+
203
+ if ((info.optWidth == null) && (info.optHeight == null)) {
204
+
205
+ info.optWidth = info.srcWidth;
206
+
207
+ info.optHeight = info.srcHeight;
208
+
209
+ } else if (info.optWidth == null) {
210
+
211
+ info.optWidth = srcRatio * info.optHeight;
212
+
213
+ } else if (info.optHeight == null) {
214
+
215
+ info.optHeight = (1 / srcRatio) * info.optWidth;
216
+
217
+ }
218
+
219
+ trgRatio = info.optWidth / info.optHeight;
220
+
221
+ if (file.height < info.optHeight || file.width < info.optWidth) {
222
+
223
+ info.trgHeight = info.srcHeight;
224
+
225
+ info.trgWidth = info.srcWidth;
226
+
227
+ } else {
228
+
229
+ if (srcRatio > trgRatio) {
230
+
231
+ info.srcHeight = file.height;
232
+
233
+ info.srcWidth = info.srcHeight * trgRatio;
234
+
235
+ } else {
236
+
237
+ info.srcWidth = file.width;
238
+
239
+ info.srcHeight = info.srcWidth / trgRatio;
240
+
241
+ }
242
+
243
+ }
244
+
245
+ info.srcX = (file.width - info.srcWidth) / 2;
246
+
247
+ info.srcY = (file.height - info.srcHeight) / 2;
248
+
249
+ return info;
250
+
251
+ },
252
+
253
+
254
+
255
+ /*
256
+
257
+ Those functions register themselves to the events on init and handle all
258
+
259
+ the user interface specific stuff. Overwriting them won't break the upload
260
+
261
+ but can break the way it's displayed.
262
+
263
+ You can overwrite them if you don't like the default behavior. If you just
264
+
265
+ want to add an additional event handler, register it on the dropzone object
266
+
267
+ and don't overwrite those options.
268
+
269
+ */
270
+
271
+ drop: function(e) {
272
+
273
+ return this.element.classList.remove("dz-drag-hover");
274
+
275
+ },
276
+
277
+ dragstart: noop,
278
+
279
+ dragend: function(e) {
280
+
281
+ return this.element.classList.remove("dz-drag-hover");
282
+
283
+ },
284
+
285
+ dragenter: function(e) {
286
+
287
+ return this.element.classList.add("dz-drag-hover");
288
+
289
+ },
290
+
291
+ dragover: function(e) {
292
+
293
+ return this.element.classList.add("dz-drag-hover");
294
+
295
+ },
296
+
297
+ dragleave: function(e) {
298
+
299
+ return this.element.classList.remove("dz-drag-hover");
300
+
301
+ },
302
+
303
+ paste: noop,
304
+
305
+ reset: function() {
306
+
307
+ return this.element.classList.remove("dz-started");
308
+
309
+ },
310
+
311
+ addedfile: function(file) {
312
+
313
+ var node, removeFileEvent, removeLink, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _results;
314
+
315
+ if (this.element === this.previewsContainer) {
316
+
317
+ this.element.classList.add("dz-started");
318
+
319
+ }
320
+
321
+ if (this.previewsContainer) {
322
+
323
+ file.previewElement = Dropzone.createElement(this.options.previewTemplate.trim());
324
+
325
+ file.previewTemplate = file.previewElement;
326
+
327
+ this.previewsContainer.appendChild(file.previewElement);
328
+
329
+ _ref = file.previewElement.querySelectorAll("[data-dz-name]");
330
+
331
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
332
+
333
+ node = _ref[_i];
334
+
335
+ node.textContent = this._renameFilename(file.name);
336
+
337
+ }
338
+
339
+ _ref1 = file.previewElement.querySelectorAll("[data-dz-size]");
340
+
341
+ for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
342
+
343
+ node = _ref1[_j];
344
+
345
+ node.innerHTML = this.filesize(file.size);
346
+
347
+ }
348
+
349
+ if (this.options.addRemoveLinks) {
350
+
351
+ file._removeLink = Dropzone.createElement("<a class=\"dz-remove\" href=\"javascript:undefined;\" data-dz-remove>" + this.options.dictRemoveFile + "</a>");
352
+
353
+ file.previewElement.appendChild(file._removeLink);
354
+
355
+ }
356
+
357
+ removeFileEvent = (function(_this) {
358
+
359
+ return function(e) {
360
+
361
+ e.preventDefault();
362
+
363
+ e.stopPropagation();
364
+
365
+ if (file.status === Dropzone.UPLOADING) {
366
+
367
+ return Dropzone.confirm(_this.options.dictCancelUploadConfirmation, function() {
368
+
369
+ return _this.removeFile(file);
370
+
371
+ });
372
+
373
+ } else {
374
+
375
+ if (_this.options.dictRemoveFileConfirmation) {
376
+
377
+ return Dropzone.confirm(_this.options.dictRemoveFileConfirmation, function() {
378
+
379
+ return _this.removeFile(file);
380
+
381
+ });
382
+
383
+ } else {
384
+
385
+ return _this.removeFile(file);
386
+
387
+ }
388
+
389
+ }
390
+
391
+ };
392
+
393
+ })(this);
394
+
395
+ _ref2 = file.previewElement.querySelectorAll("[data-dz-remove]");
396
+
397
+ _results = [];
398
+
399
+ for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
400
+
401
+ removeLink = _ref2[_k];
402
+
403
+ _results.push(removeLink.addEventListener("click", removeFileEvent));
404
+
405
+ }
406
+
407
+ return _results;
408
+
409
+ }
410
+
411
+ },
16
412
 
17
413
  ```
18
-
19
- ActionView::MissingTemplate (Missing template shops/create, application/create with {:locale=>[:en], :formats=>[:all], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :coffee, :arb, :jbuilder]}. Searched in:
20
-
21
- ```
22
-
23
- とありますので、テンプレートが見つからないが原因部分かと見ています。
24
-
25
- その対策としてコントローラに挙動を指定しました。
26
-
27
- ```Ruby
28
-
29
- format.any
30
-
31
- format.html { render html: @shop }
32
-
33
- format.json { render json: @shop }
34
-
35
- ```
36
-
37
-
38
-
39
- ですが、上記のエラーは変わらずに出てしまいます。
40
-
41
- 恐れ入りますが不足している点を教えていただけませんでしょうか。
42
-
43
-
44
-
45
-
46
-
47
- ---
48
-
49
-
50
-
51
- 以下元ファイルです。
52
-
53
- ```
54
-
55
- #Gemをインストール
56
-
57
- gem 'dropzonejs-rails', '~> 0.7.3'
58
-
59
- ```
60
-
61
- app/assets/javascripts/application.js
62
-
63
- ```JavaScript
64
-
65
- //= require dropzone
66
-
67
- ```
68
-
69
- app/assets/stylesheets/application.css
70
-
71
- ```CSS
72
-
73
- *= require dropzone/basic
74
-
75
- *= require dropzone/dropzone
76
-
77
- ```
78
-
79
- app/models/shop.rb
80
-
81
- ```Ruby
82
-
83
- class Shop < ActiveRecord::Base
84
-
85
- #attachmentを子に指定します
86
-
87
- has_many :attachments, dependent: :destroy
88
-
89
- end
90
-
91
- ```
92
-
93
- app/models/attachment.rb
94
-
95
- ```Ruby
96
-
97
- class Attachment < ActiveRecord::Base
98
-
99
- #Shopを親モデルに指定します
100
-
101
- belongs_to :shop
102
-
103
- end
104
-
105
- ```
106
-
107
- app/controllers/shops_controller.rb
108
-
109
- ```Ruby
110
-
111
- class ShopsController < ApplicationController
112
-
113
-
114
-
115
- def new
116
-
117
- @shop = Shop.new
118
-
119
- #attachmentをビルドします
120
-
121
- @shop.attachments.build
122
-
123
- respond_with(@shop)
124
-
125
- end
126
-
127
-
128
-
129
- def create
130
-
131
- @shop = current_user.shops.build(shop_params)
132
-
133
- respond_to do |format|
134
-
135
- if @shop.save
136
-
137
- format.any
138
-
139
- format.html { render html: @shop }
140
-
141
- format.json { render json: @shop }
142
-
143
- else
144
-
145
- format.html { render action: 'new' }
146
-
147
- end
148
-
149
- end
150
-
151
-
152
-
153
- def shop_params
154
-
155
- params.require(:shop).permit(:name,
156
-
157
- attachments_attributes: [:id, :image, :_destroy]
158
-
159
- )
160
-
161
- end
162
-
163
- end
164
-
165
- ```
166
-
167
- app/views/documents/new.html.erb
168
-
169
- ```
170
-
171
- <h1>New shop</h1>
172
-
173
-
174
-
175
- <%= render 'form' %>
176
-
177
-
178
-
179
- <%= link_to 'Back', shops_path %>
180
-
181
- ```
182
-
183
- app/views/documents/_form.html.erb
184
-
185
- ```
186
-
187
- <%= form_for(@shop, html: {multipart: true, class: 'dropzone', id: 'my-awesome-dropzone', remote: true}) do |f| %>
188
-
189
-
190
-
191
- <div class="row">
192
-
193
- <div class="col-md-10 col-md-offset-1">
194
-
195
- <%= render partial: 'upload_photos_form', locals: { shop_id: @shop.id } %>
196
-
197
- </div>
198
-
199
- </div>
200
-
201
-
202
-
203
- <%= f.label :name %>
204
-
205
- <%= f.text_field :name, :size => '10' %><br>
206
-
207
- <% end %>
208
-
209
- ```
210
-
211
- app/views/documents/_upload_photos_form.html.erb
212
-
213
- ```
214
-
215
- <div class="fallback">
216
-
217
- <%= file_field_tag('shop[attachments]') %>
218
-
219
- </div>
220
-
221
- ```
222
-
223
- コンソール
224
-
225
- ```
226
-
227
- Started GET "/shops/new" for ::1 at 2016-12-30 10:46:45 +0700
228
-
229
- Processing by ShopsController#new as HTML
230
-
231
- User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1 [["id", 1]]
232
-
233
- Rendered shops/_upload_photos_form.html.erb (0.1ms)
234
-
235
- Rendered shops/_form.html.erb (13.9ms)
236
-
237
- Rendered shops/new.html.erb within layouts/application (15.5ms)
238
-
239
- Completed 200 OK in 353ms (Views: 348.5ms | ActiveRecord: 0.1ms)
240
-
241
-
242
-
243
-
244
-
245
- Started POST "/shops" for ::1 at 2016-12-30 10:46:58 +0700
246
-
247
- Processing by ShopsController#create as JSON
248
-
249
- Parameters: {"utf8"=>"✓", "shop"=>{"name"=>"テスト"}, "commit"=>"登録", @original_filename="253_main.jpg", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"file\"; filename=\"253_main.jpg\"\r\nContent-Type: image/jpeg\r\n">}
250
-
251
- User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1 [["id", 1]]
252
-
253
- Unpermitted parameter: name_en
254
-
255
- (0.2ms) begin transaction
256
-
257
- SQL (0.7ms) INSERT INTO "shops" ("name", "user_id", "created_at", "updated_at") VALUES (?,?,?,?) [["name", "テスト"], ["user_id", 1], ["created_at", "2016-12-30 03:46:58.203299"], ["updated_at", "2016-12-30 03:46:58.203299"]]
258
-
259
- (1.0ms) commit transaction
260
-
261
- Completed 200 OK in 55ms (Views: 2.1ms | ActiveRecord: 6.1ms)
262
-
263
-
264
-
265
-
266
-
267
- Started POST "/shops" for ::1 at 2016-12-30 10:47:00 +0700
268
-
269
- Processing by ShopsController#create as JS
270
-
271
- Parameters: {"utf8"=>"✓", "shop"=>{"name"=>"テスト"}, "commit"=>"登録"}
272
-
273
- User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1 [["id", 1]]
274
-
275
- Unpermitted parameter: name_en
276
-
277
- (0.1ms) begin transaction
278
-
279
- SQL (0.5ms) INSERT INTO "shops" ("name", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["name", "テスト"], ["user_id", 1], ["created_at", "2016-12-30 03:47:00.724796"], ["updated_at", "2016-12-30 03:47:00.724796"]]
280
-
281
- (2.3ms) commit transaction
282
-
283
- Completed 500 Internal Server Error in 51ms (ActiveRecord: 3.3ms)
284
-
285
-
286
-
287
- ActionView::MissingTemplate (Missing template shops/create, application/create with {:locale=>[:en], :formats=>[:all], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :coffee, :arb, :jbuilder]}. Searched in:
288
-
289
- * "/Users/yousukesatou/projects/HerokuApp/app/views"
290
-
291
- * "/Users/yousukesatou/projects/HerokuApp/vendor/bundle/ruby/2.3.0/bundler/gems/active_admin-4f494073c6c0/app/views"
292
-
293
- * "/Users/yousukesatou/projects/HerokuApp/vendor/bundle/ruby/2.3.0/gems/twitter-bootstrap-rails-3.2.2/app/views"
294
-
295
- * "/Users/yousukesatou/projects/HerokuApp/vendor/bundle/ruby/2.3.0/gems/devise-3.5.1/app/views"
296
-
297
- * "/Users/yousukesatou/projects/HerokuApp/vendor/bundle/ruby/2.3.0/gems/kaminari-0.15.1/app/views"
298
-
299
- ):
300
-
301
- app/controllers/shops_controller.rb:60:in `create'
302
-
303
-
304
-
305
-
306
-
307
- Rendered vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.4/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb (0.4ms)
308
-
309
- ```