问题
I am writting an application 100% ajax with rails 3.2.8
Everything was going great until I tried to upload photos of the employees to the employee management module.
This is part of my code:
At the Controller:
class EmpleadosController < ApplicationController
respond_to :js
before_filter :require_user
def index
@empleados = Empleado.paginate( page: params[ :page ],
joins: [:user,:contacto],
select: 'empleados.id as id, empleados.user_id, empleados.contratado_el, empleados.despedido_el, empleados.nss, empleados.sueldo_base_semanal, empleados.comentarios, empleados.foto_file_name, empleados.foto_content_type, empleados.foto_file_size, empleados.foto_updated_at, users.username as username, contactos.salutacion_id as salutacion_id, contactos.id as contacto_id, contactos.nombres as nombres, contactos.apellidos as apellidos'
).sorted( params[ :sort ] )
end
def new
@empleado = Empleado.new
end
def create
@empleado = Empleado.new(params[:empleado])
@empleado.sueldo_base_semanal = params[:empleado][:sueldo_base_semanal].gsub(',','').gsub('$','').to_f
if @empleado.save
redirect_to empleados_path
else
render action: 'new'
end
end
...
Now for the view (I am using HAML):
= form_for( @empleado, remote: true, html: {multipart: true} ) do |f|
= show_me_the_errors @empleado
%table.captura
%tr
%td.etiqueta
= f.label :user_id
%td.campo
= f.select :user_id,
User.usuarios_no_asignados,
{ include_blank: true },
{ tabindex: 1 }
= image_tag 'nuevo_24.png',
style: 'vertical-align: bottom;',
id: 'empleado_nuevo_usuario'
... ( 5 more text fields ) ...
%tr
%td.etiqueta
= f.label :foto
%td.campo
= f.file_field :foto,
accept: 'image/png,image/gif,image/jpeg'
The thing is that while there is not selected file for upload, everything works fine, the command respond_to :js
works as it should be in all interactions between create
with index
and new
.
But, when you select an image, all the interactions after create
with index
and new
become HTML
completely ignoring the respond_to :js
, I mean, the form for
behaves just like if the remote: true
wasn't there
When everything works well, the URL is localhost:3000 and never changes, but when I select an image to upload, the URL after crete
becomes localhost:3000/empleados
Does any one have any clue about this? I have been trying to solve this for the last 3 dyas and failed.
Thaks in advance.
回答1:
OK, after several days trying to find the problem I started working on a workaround. So this is it:
1) I created a DB Table for temprary storage, with the ID field set without autoincrement, and with the normal field names:
mysql> describe imagens;
+---------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+--------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| imagen_file_name | varchar(500) | YES | | NULL | |
| imagen_content_type | varchar(500) | YES | | NULL | |
| imagen_file_size | int(11) | YES | | NULL | |
| imagen_updated_at | datetime | YES | | NULL | |
| created_at | datetime | NO | | NULL | |
| updated_at | datetime | NO | | NULL | |
| lock_version | int(11) | NO | | 0 | |
+---------------------+--------------+------+-----+---------+-------+
8 rows in set (0.00 sec)
2) at the view (_form.html.haml
):
-# this variable will be used as primary key for identifying the image to upload in the database
- ale = Time.now.to_i
3) at the view (_form.html.haml
):
I separated the file_field
tag
-# FORM for general data input
= form_for( @empleado, remote: true ) do |f|
...
then, inside that form I add, a hidden file with the variable ale
and a pretty small iframe
-# I use it in order to find out for wich record to search at the temporary DBTable
= hidden_field_tag :ale, ale
-# this IFRAME will be used to catch the error message returned by rails when uploading the image, it will be invisible
%iframe{src: '#', frameborder:0, height: 0, width: 0, id: 'nulo', name: 'nulo'}
and encapsulated in its own form_for
tag, but without any kind of submit
or commit
button.
= form_for( @imagen, remote: true, html: {multipart: true, target: 'nulo'} ) do |f|
-# used to set the primary key to this value
= hidden_field_tag :ale, ale
= f.file_field :imagen, {style: 'vertical-align: middle;'}
then a little javascript to upload the image when the user choose one, it does the submit by an event trigger:
:javascript
$('#imagen_imagen').change(function(){
$('#new_imagen').submit();
});
4) this is the content of the model for imagen (models/imagen.rb):
class Imagen < ActiveRecord::Base
attr_accessible :imagen
has_attached_file :imagen,
styles: { t100: '100x100>', t300: '300x300X', t600: '600x600' },
convert_options: { all: '-strip' },
path: ":rails_root/public/system/:class/:attachment/:id/:style/:filename",
url: "/system/:class/:attachment/:id/:style/:filename",
hash_secret: 'topsecret'
validates_attachment_size :imagen,
less_than: 250.kilobytes,
message: (I18n.t :mensajes)[:paperclip][:grande]
end
5) this is the code at controllers/imagens_controller.rb :
class ImagensController < ApplicationController
respond_to :js
# by the way, this sline is from authlogic, a great gem to control the access to your site
before_filter :require_user
def create
@imagen = Imagen.new(params[:imagen])
@imagen.id = params[:ale]
@imagen.save
render text: ''
end
end
6) now, in controller/empleados_controller.rb the code is:
def create
@empleado = Empleado.new(params[:empleado])
if @empleado.save
imagen = Imagen.find(params[:ale].to_i)
if imagen
@empleado.foto = imagen.imagen
@empleado.save
imagen.destroy
end
redirect_to empleados_path
else
@imagen = Imagen.new
render action: 'new'
end
end
7) Glosary:
imagen = image
empleado = employee
empleados = staff
ale = short name for aleatorio, I mean, random
foto = picture o photograpy
8) Conclussion:
It works !!!
9) To-Do:
The drawback is that after you upload an image, it will be stored at the database, and then you can cancel the form or change page, that will leave the record and picture alive.
At the beginning I will make a link in my admin module that destroys all records from the Table holding the temporary images, with something like Imagen.all.each{|x| x.destroy }
Later on, I will write a script that at 2:00 a.m. executes that code.
来源:https://stackoverflow.com/questions/12955288/trouble-with-paperclip-and-ajax-with-rails-3-2-8