ruby on rails - images - Subida programática de Carrierwave
rails image upload (2)
De acuerdo, tengo una solución de trabajo. Voy a explicar mejor lo que hice para que otros puedan aprender de mi experiencia. Aquí va:
Suponiendo que tienes una aplicación para iPhone que toma una foto:
//handle the image that has just been selected
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
//get the image
UIImage* image = [info valueForKey:@"UIImagePickerControllerOriginalImage"];
//scale and rotate so you''re not sending a sideways image -> method provided by http://blog.logichigh.com/2008/06/05/uiimage-fix/
image = [self scaleAndRotateImage:image];
//obtain the jpeg data (.1 is quicker to send, i found it better for testing)
NSData *imageData = [NSData dataWithData:UIImageJPEGRepresentation(image, .1)];
//get the data into a string
NSString* imageString = [NSString stringWithFormat:@"%@", imageData];
//remove whitespace from the string
imageString = [imageString stringByReplacingOccurrencesOfString:@" " withString:@""];
//remove < and > from string
imageString = [imageString substringWithRange:NSMakeRange(1, [imageString length]-2)];
self.view.hidden = YES;
//dismissed the camera
[picker dismissModalViewControllerAnimated:YES];
//posts the image
[self performSelectorInBackground:@selector(postImage:) withObject:imageString];
}
- (void)postImage:(NSString*)imageData
{
//image string formatted in json
NSString* imageString = [NSString stringWithFormat:@"{/"image/": /"%@/", /"authenticity_token/": /"/", /"utf8/": /"✓/"}", imageData];
//encoded json string
NSData* data = [imageString dataUsingEncoding:NSUTF8StringEncoding];
//post the image
[API postImage:data];
}[/code]
Then for the post:
[code]+(NSArray*)postImage:(NSData*) data
{
//url that you''re going to send the image to
NSString* url = @"www.yoururl.com/images";
//pretty self explanatory request building
NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:url]];
[request setTimeoutInterval:10000];
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[request setHTTPMethod: @"POST"];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[request setHTTPBody:data];
NSError *requestError;
NSURLResponse *urlResponse = nil;
NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&requestError];
return [API generateArrayWithData:result];
}
En el lado de los rieles, establecí un método específico para manejar imágenes móviles, esto debería ayudarlo a publicar la imagen en su cuenta de Amazon S3 a través de Carrierwave:
def post
respond_to do |format|
format.json {
#create a new image so that you can call it''s class method (a bit hacky, i know)
@image = Image.new
#get the json image data
pixels = params[:image]
#convert it from hex to binary
pixels = @image.hex_to_string(pixels)
#create it as a file
data = StringIO.new(pixels)
#set file types
data.class.class_eval { attr_accessor :original_filename, :content_type }
data.original_filename = "test1.jpeg"
data.content_type = "image/jpeg"
#set the image id, had some weird behavior when i didn''t
@image.id = Image.count + 1
#upload the data to Amazon S3
@image.upload(data)
#save the image
if @image.save!
render :nothing => true
end
}
end
end
Esto funciona para mí para publicar y creo que debería ser bastante ampliable. Para los métodos de clase:
#stores the file
def upload(file)
self.path.store!(file)
end
#converts the data from hex to a string -> found code here http://4thmouse.com/index.php/2008/02/18/converting-hex-to-binary-in-4-languages/
def hex_to_string(hex)
temp = hex.gsub("/s", "");
ret = []
(0...temp.size()/2).each{|index| ret[index] = [temp[index*2, 2]].pack("H2")}
file = String.new
ret.each { |x| file << x}
file
end
No digo que este código sea perfecto, ni siquiera por un disparo largo. Sin embargo, funciona para mí. Estoy abierto a sugerencias si alguien piensa que podría mejorarse. ¡Espero que esto ayude!
En este momento, en mi aplicación Rails, estoy usando Carrierwave para subir archivos a Amazon S3. Estoy usando un selector de archivos y un formulario para seleccionar y enviar el archivo, esto funciona bien.
Sin embargo, ahora intento hacer publicaciones desde una aplicación de iPhone y recibo el contenido del archivo. Me gustaría crear un archivo usando estos datos y luego subirlo usando Carrierwave para poder recuperar la ruta correcta.
El modelo de archivo de mayo consiste en:
path
file_name
id
user_id
donde la ruta es la url de Amazon S3. Me gustaría hacer algo como esto para construir los archivos:
data = params[:data]
~file creation magic using data~
~carrierwave upload magic using file~
@user_id = params[:id]
@file_name = params[:name]
@path = path_provided_by_carrierwave_magic
File.build(@user_id, @file_name, @path)
Realmente amaría a alguien que me señale en la dirección correcta. ¡Gracias!
Esto es lo que escribí para realizar una carga en s3 desde una aplicación ios a través de carrierwave:
Primero el modelo de Foto
class Photo
include Mongoid::Document
include Mongoid::Timestamps
mount_uploader :image, PhotoImageUploader
field :title, :type => String
field :description, :type => String
end
Segundo en el Api :: V1 :: PhotosController
def create
@photo = current_user.photos.build(params)
if @photo.save
render :json => @photo.to_json, :status=>201
else
render :json => {:errors => @photo.errors}.to_json, :status=>403
end
end
Entonces la llamada desde mi aplicación de iPhone usando AFNetworking
-(void) sendNewPhoto
{
NSURL *url = [NSURL URLWithString:@"http://myserverurl.com"];
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:_photoTitle.text, @"title", _photoDescription.text, @"description",nil];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
NSString *endUrl = [NSString stringWithFormat:@"/api/v1/photos?auth_token=%@", [[User sharedInstance] token]];
NSData *imageData = UIImageJPEGRepresentation(_photo.image, 1.0);
NSURLRequest *request = [httpClient multipartFormRequestWithMethod:@"POST" path:endUrl parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:imageData name:@"image" fileName:@"image.jpg" mimeType:@"image/jpg"];
}];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSLog(@"%@", JSON);
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(@"Error creating photo!");
NSLog(@"%@", error);
}];
[operation start];
}
En la respuesta JSON puedo obtener la nueva instancia de Foto con el atributo image.url establecido en la url en el s3.