2012-03-18 16 views
27

これに似た質問があることは知っていますが、まだ良い答えが見つかりませんでした。画像、クリップアタッチメント:Rails JSON APIにファイルを送信する

has_attached_file :image 

今、私は画像を送信することを読んだ私は何をする必要があることは、私と呼ばれるものを含め、いくつかの異なる属性を含み方法を、作成のいずれかにオブジェクトの説明を送っていますbase64で画像をエンコードしてデコードすることでJSONで直感的に行うことができますが、それは私の厄介な解決策のように感じます。より良い方法が必要です。

もう1つの解決策は、1つより多くのmultipart/form-dataリクエストを送信することです。LEEjava describes here.この問題は、リクエストパラメータがRails 3.2.2で正しく解釈されず、JSON.parseがparamsを解析しようとするか、あるいは何かを誤って解釈しているRailsかもしれません。

Started POST "/api/v1/somemodel.json?token=ZoipX7yhcGfrWauoGyog" for 127.0.0.1 at 2012-03-18 15:53:30 +0200 Processing by Api::V1::SomeController#create as JSON Parameters: {"{\n
\"parentmodel\": {\n \"superparent_id\": 1,\n
\"description\": \"Enjoy the flower\",\n \"\": "=>{"\n
{\n \"someattribute\": 1,\n
\"someotherattribute\": 2,\n \"image\": \"image1\"\n
}\n "=>{"\n }\n}"=>nil}}, "token"=>"ZoipX7yhcGfrWauoGyog"}

これを読むのは非常に難しいです。 JSON.parse(のparams [:parentmodel])は、ここでは不可能である、と私はできないJSON.parse(のparams)のいずれかのためにトークンの属性の、JSON.parse(のparams)は、このエラーがスローされます:

TypeError (can't convert ActiveSupport::HashWithIndifferentAccess into String)

これは、私がこの問題に完全に間違っていると信じるように導くか、何かをやっているだけです。いずれにせよ、私は何かについて間違っていると確信することができます。 :)

もっと良い方法がありますか?誰かが私をガイド/チュートリアルに導くことができますか、これにどのようにアプローチすべきかを説明する答えを書くことができますか?

は、事前にありがとう

UPDATE: だから私は実際にはなく、テストだけで、今働いてそれを持っています。私はこれがどのように機能するかは完全には分かっていないが、おそらく誰かが私のためにギャップを埋めることができるだろうか?これはテストコードの一部です(画像:fixture_file_upload(...)は重要な部分です)。

parts_of_the_object = { someattribute: 0, someotherattribute: 0, image: fixture_file_upload('/images/plot.jpg', 'image/jpg') } 

私のparams []は、通常のHTMLフォームが奇妙な(そして素晴らしい)である、提出されたようになっています

Parameters: {"superparentid"=>"1", "plots"=>[{"someattribute"=>"0", "someotherattribute"=>"0", "image"=>#<ActionDispatch::Http::UploadedFile:0x007f812eab00e8 @original_filename="plot.jpg", @content_type="image/jpg", @headers="Content-Disposition: form-data; name=\"plots[][image]\"; filename=\"plot.jpg\"\r\nContent-Type: image/jpg\r\nContent-Length: 51818\r\n", @tempfile=#<File:/var/folders/45/rcdbb3p50bl2rgjzqp3f0grw0000gn/T/RackMultipart20120318-1242-1cn036o>>}], "token"=>"4L5LszuXQMY6rExfifio"} 

要求が同じように作られており、ポスト要求がRSpecので構成されています

post "/api/v1/mycontroller.json?token=#{@token}", thefull_object 

だから私はそれがすべて働いている。私はちょうどそれがどのように動作するのか分かりません! RSpecだけでなく、私自身もこのようなレスポンスを作りたいと思っています。 :-)

答えて

38

私は実際には非常に似たようなことをするために昨日この質問で恐ろしい時間を過ごしていた。実際には、質問を書いた:Base64 upload from Android/Java to RoR Carrierwave

アップロードされたイメージオブジェクトをコントローラに作成し、それをパラメータに戻して注入したのはどうだったか。

この具体例では、JSONが埋め込みファイルをサポートしていないため、base64ファイルを取得してシステムに一時ファイルとして保存してから、そのUploadedFileオブジェクトを作成していますそれをパラメータに再注入する。どのように見えるか、私のJSON/paramsは

:ここ

picture {:user_id => "1", :folder_id => 1, etc., :picture_path {:file => "base64 awesomeness", :original_filename => "my file name", :filename => "my file name"}} 

は私のコントローラは、今のように見えるものです:

# POST /pictures 
    # POST /pictures.json 
    def create 

    #check if file is within picture_path 
    if params[:picture][:picture_path]["file"] 
     picture_path_params = params[:picture][:picture_path] 
     #create a new tempfile named fileupload 
     tempfile = Tempfile.new("fileupload") 
     tempfile.binmode 
     #get the file and decode it with base64 then write it to the tempfile 
     tempfile.write(Base64.decode64(picture_path_params["file"])) 

     #create a new uploaded file 
     uploaded_file = ActionDispatch::Http::UploadedFile.new(:tempfile => tempfile, :filename => picture_path_params["filename"], :original_filename => picture_path_params["original_filename"]) 

     #replace picture_path with the new uploaded file 
     params[:picture][:picture_path] = uploaded_file 

    end 

    @picture = Picture.new(params[:picture]) 

    respond_to do |format| 
     if @picture.save 
     format.html { redirect_to @picture, notice: 'Picture was successfully created.' } 
     format.json { render json: @picture, status: :created, location: @picture } 
     else 
     format.html { render action: "new" } 
     format.json { render json: @picture.errors, status: :unprocessable_entity } 
     end 
    end 
    end 

唯一のことは、この時点で行うには、左の一時ファイルを削除することで、私はこれができると信じていますtempfile.delete

私はこれがあなたの質問に役立つことを願っています!昨日、私は一日中解決策を探していました。私が見てきたことはすべて終わりです。しかし、これは私のテストケースで動作します。

+0

dev/prodモードで動作しない場合は、数日前に解決策を見つけましたが、答えを書いてください。これはあなたのものによく似ていますが、私はモデルでそれをやっています(Base64データをimage_data属性に直接送ります)。私はあなたのソリューションがより好きです。それがどうなるか教えてください。できれば助けます。 –

+0

私は答えが正しいことから、私は賞金を授与しています。 –

+0

これは良い答えですが、少なくともRails 3/Ruby 1.9にはいくつかの小さな穴があります。 まず、書き込み後に 'tempfile.rewind()'を確認してください。そうでなければ、長さ0のファイルが得られます。 – Shannon

8

TomJが良い答えを出しましたが、少なくともRails 3/Ruby 1.9にはいくつかの小さな穴があります。

まず、paramsオブジェクト内のUploadedFileオブジェクトである可能性のある[]を呼び出さないでください。たとえば、最初に.is_a?(Hash)であることを確認してください。

また、書き込み後に必ずtempfile.rewind()を確認してください。そうしないと、長さが0のファイルが作成されます。

UploadedFileのコンストラクタのパラメータにある:original_filenameのキーは不要/未使用です。一方、:typeキーを提供することができます。タイプの値を見つけるための簡単な方法は、ここでmime_type = Mime::Type.lookup_by_extension(File.extname(original_filename)[1..-1]).to_s

で適用された変更とバージョンです:

# POST /pictures 
# POST /pictures.json 
def create 

    #check if file is within picture_path 
    if params[:picture][:picture_path].is_a?(Hash) 
    picture_path_params = params[:picture][:picture_path] 
    #create a new tempfile named fileupload 
    tempfile = Tempfile.new("fileupload") 
    tempfile.binmode 
    #get the file and decode it with base64 then write it to the tempfile 
    tempfile.write(Base64.decode64(picture_path_params["file"])) 
    tempfile.rewind() 

    mime_type = Mime::Type.lookup_by_extension(File.extname(original_filename)[1..-1]).to_s 
    #create a new uploaded file 
    uploaded_file = ActionDispatch::Http::UploadedFile.new(
     :tempfile => tempfile, 
     :filename => picture_path_params["filename"], 
     :type => mime_type) 

    #replace picture_path with the new uploaded file 
    params[:picture][:picture_path] = uploaded_file 
    end 

    @picture = Picture.new(params[:picture]) 
    respond_to do |format| 
    if @picture.save 
     format.html { redirect_to @picture, notice: 'Picture was successfully created.' } 
     format.json { render json: @picture, status: :created, location: @picture } 
    else 
    format.html { render action: "new" } 
    format.json { render json: @picture.errors, status: :unprocessable_entity } 
    end 
end 

エンド

+0

{:avatar => ["Paperclip :: Errors :: NotIdentifiedByImageMagickError"、 "Paperclip :: Errors :: NotIdentifiedByImageMagickError"]}>何か考えていますか? – ajbraus

関連する問題