with tutorial simple scotch restful rails only creating create ruby-on-rails json ruby-on-rails-3.2

ruby on rails - tutorial - Envío de archivos a una API JSON de Rails



ruby restful (3)

Ayer me estaba pasando muy mal con esta pregunta para hacer algo muy similar. De hecho, escribí la pregunta: Carga de Base64 desde Android / Java a RoR Carrierwave

Todo se redujo a crear ese objeto de imagen cargado en el controlador y luego volver a inyectarlo en los parámetros.

Para este ejemplo específico, estamos tomando un archivo base64 (que asumo que tienes, ya que JSON no admite archivos incrustados) y lo guardamos como un archivo temporal en el sistema, entonces estamos creando ese objeto UploadedFile y finalmente lo reinyectamos en el archivo. params

Cómo se ve mi json / params:

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

Aquí es como se ve mi controlador ahora:

# 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

Lo único que queda por hacer en este punto es eliminar el archivo temp, que creo que se puede hacer con el tempfile.delete

Espero que esto ayude con su pregunta! Pasé todo el día buscando una solución ayer, y todo lo que he visto es un callejón sin salida. Esto, sin embargo, funciona en mis casos de prueba.

Sé que hay preguntas similares a esta, pero todavía no he encontrado una buena respuesta. Lo que debo hacer es enviar una descripción de un objeto a uno de mis métodos de creación, que incluye algunos atributos diferentes, incluido uno llamado: imagen, un adjunto de clip:

has_attached_file :image

Ahora he leído que el envío de la imagen se puede hacer directamente en JSON mediante la codificación y decodificación de la imagen como base64, pero para mí es una solución sucia. Debe haber mejores maneras.

Otra solución es enviar una solicitud multipart / form-data, como la que LEEjava describe aquí. El problema con eso es que los parámetros de solicitud no se interpretan correctamente en Rails 3.2.2, y JSON.parse escupe un error cuando intenta analizar los parámetros, o tal vez es Rails quien está malinterpretando algo.

Comenzó la POST "/api/v1/somemodel.json?token=ZoipX7yhcGfrWauoGyog" para 127.0.0.1 a 2012-03-18 15:53:30 +0200 Procesando por Api :: V1 :: SomeController # create as JSON Parameters: {" {/norte
/ "parentmodel /": {/ n / "superparent_id /": 1, / n
/ "descripción /": / "Disfruta de la flor /", / n / "/": "=> {" / n
{/ n / "someattribute /": 1, / n
/ "algún otro atributo /": 2, / n / "imagen /": / "imagen1 /" / n
} / n "=> {" / n} / n} "=> nil}}," token "=>" ZoipX7yhcGfrWauoGyog "}

Es muy difícil leer eso, lo siento. JSON.parse (params [: parentmodel]) no es posible aquí, y no puedo JSON.parse (params) debido al atributo token, JSON.parse (params) emite este error:

TypeError (no se puede convertir ActiveSupport :: HashWithIndifferentAccess en String)

Lo que me lleva a creer que estoy abordando este problema totalmente equivocado, o simplemente estoy haciendo algo. De cualquier manera, podemos estar seguros de que estoy equivocado en algo. :)

¿Hay una mejor manera de hacer esto? ¿Alguien puede indicarme alguna guía / tutorial o escribir una respuesta que describa cómo debo abordar esto?

Gracias de antemano

ACTUALIZACIÓN: Así que realmente lo tengo funcionando ahora, pero solo en las pruebas. No estoy totalmente seguro de cómo funciona esto, pero ¿quizás alguien pueda llenar los vacíos por mí? Esto es parte del código de prueba (la imagen: fixture_file_upload (...) es la parte importante).

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

Mis parámetros [] parece que se envió un formulario HTML normal, lo cual es extraño (y asombroso):

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"}

La solicitud se realiza como y la solicitud de publicación se realiza con rspec:

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

Así que lo tengo todo funcionando. ¡Simplemente no sé cómo funciona exactamente! Quiero ser capaz de crear una respuesta como esta por mí mismo, no solo de RSpec. :-)



TomJ dio una buena respuesta, pero al menos en Rails 3 / Ruby 1.9 hay algunos agujeros menores.

Primero, no intentes llamar [] a lo que podría ser un objeto UploadedFile en tu objeto params. Asegúrese de verificar que sea .is_a?(Hash) primero, por ejemplo.

Además, asegúrese de tempfile.rewind() después de escribir, de lo contrario obtendrá archivos con una longitud de 0.

La clave :original_filename en los parámetros para el constructor de UploadedFile es innecesaria / no utilizada. Por otro lado, es posible que desee proporcionar una clave de :type . Una forma fácil de encontrar el valor para el tipo es mime_type = Mime::Type.lookup_by_extension(File.extname(original_filename)[1..-1]).to_s

Aquí hay una versión con los cambios aplicados:

# 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

fin