canvasの画像をtoDataURL()を使ってRailsのcarrierwaveで保存するまで
個人的にとてもタイムリーな記事を参考に試してみた。
[rails]base64エンコードされた画像をcarrierwaveに保存する | hello-world.jp.net
だがRails4のstrong parametersの理解不足で余計な時間が掛かってしまった。
まずはデータの流れ。
<%= form_for(@item) do |f| %> <%= f.file_field :image %> <%= f.hidden_field :remote_image_url %><!-- 今回の修正で追加 --> <%= f.hidden_field :user_id, :value => current_user.id %> <% end %>
元々このようなフォームを使用していた。
「file_fieldでローカルの画像を取得 → その値をJavaScriptで変更監視 → canvasにその画像を書き出す → JavaScriptで画像を操作」まではできていた。
そこからcanvas.toDataURL()で生成した文字列をcarrierwaveで利用可能なremote_image_urlでサーバーにポストする流れだ。
// サーバーにポストする操作 $("#canvas_output").on("click", function () { var _form = $("#new_item"); var canvas = document.getElementById("canvas"); var canvas_data = canvas.toDataURL(); $("#item_image").val(""); //画像データを二重に送信するのを防ぐ $("#item_remote_image_url").val(canvas_data); _form.submit(); });
これを受けるcontrollerの記述が問題だった。先に正しいバージョン
def create tmp_item_params = item_params image_data = base64_conversion(tmp_item_params[:remote_image_url]) tmp_item_params[:image] = image_data tmp_item_params[:remote_image_url] = nil @item = Item.new(tmp_item_params) @item.save redirect_to edit_item_path(@item) end private def set_item @item = Item.find(params[:id]) end def item_params params.require(:item).permit(:title, :image, :explanation, :user_id, :remote_image_url) end
当初、createの記述が誤っていた。
def create image_data = base64_conversion(tmp_item_params[:remote_image_url]) item_params[:image] = image_data item_params[:remote_image_url] = nil @item = Item.new(item_params) @item.save redirect_to edit_item_path(@item) end
わかってみれば単純な話で、item_paramsというメソッドを変数と勘違いし、値の代入を試みてしまい上手くいかなかったという話。