Giba

ジバブログ - Webエンジニアリングとマーケティング

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というメソッドを変数と勘違いし、値の代入を試みてしまい上手くいかなかったという話。