Algo muy curioso con el find()

Hola a todos nuevamente, les comento cual es mi problema y de verdad que
no
se porque me esta pasando esto porque es algo muy estupido…
bueno les comento que en mi proyecto una vez que el usuario se suscribe
en
el site yo creo el usuario en la tabla users y luego obtengo el id y
incluyo
en la tabla alumno los demas datos esto es lo que hago en el controller
de
suscripcione

password = 100000 + rand(899999)

@user = User.new(:login => params[:suscripcione][:login],
:grupousuario_id
=>“1”, :password => password.to_s, :password_confirmation =>
password.to_s,
:status => “A”, :denusu => params[:suscripcione][:nombre], :email =>
params[:suscripcione][:login], :created_at => Time.now)
@user.save

@u = User.find(:all,:conditions => “login = '”+
params[:suscripcione][:login]+ “’”) #para obtener el id del usuario que
acabo de crear

#luego incluyo en Alumno los demas datos

@alumno = Alumno.new(:nombre => params[:suscripcione][:nombre],
:apellido =>
params[:suscripcione][:apellido], :sexo =>
params[:suscripcione][:sexo],
:user_id => @u.id)

Al parecer todo bien pero da el siguiente error que no lo entiendo:

ActiveRecord::StatementInvalid in SuscripcionesController#create

PGError: ERROR: inserción o actualización en la tabla «alumnos» viola
la llave foránea «fk_alumnos_users»
DETAIL: La llave (user_id)=(-612873488) no está presente en la tabla
«users».
: INSERT INTO alumnos (“nombre”, “apellido”, “sexo”, “user_id”)
VALUES(E’Julio’, E’Valencia’, E’M’, -612873488)

Mi pregunta y gran duda es porque rails me esta devolviendo el id del
user -612873488? cuando consulto en la base de datos el id de ese
nuevo usuario es => 21

No entiendo alguien me puede explicar que esta pasando alli?
Primera vez que me pasa esto, hice pruebas con find_by_sql,
find_by_login, find(:last) y me da el mismo error y el mismo user_id =
-612873488

Hola Manuel, no hay nada raro, solo es cuestion de conocer un poco mas
ActiveRecord, estas obteniendo el valor “-612873488” por que es el
identificador del objeto del tipo Array que has obtenido mediante @u =
User.find(:all…), el metodo find con el parametro :all, te devuelve un
Array asi el resultado sea un solo registro, si quieres obtener solo un
registro entonces debes omitir ese parametro, otro detalle esa consulta
que
haces esta demas, ya que tienes el id del usuario creado disponible
mediante: @user.id.

Saludos.

El día 21 de julio de 2008 19:54, Manuel P. <
[email protected]> escribió:

hola ruben gracias por la explicacion se me olvido comentar que yo
tambien
use el @user.id y me dio este error

ActiveRecord::StatementInvalid in SuscripcionesController#create

PGError: ERROR: no existe la relación «alumnos_id_seq»
: SELECT currval(‘alumnos_id_seq’)

en los modelos tengo:
belongs_to :user ==> en la clase modelo Alumno
belongs_to :alumno ==> en la clase modelo User

sigo sin intender…

El día 22 de julio de 2008 21:18, Ruben. D. [email protected]
escribió:

bueno creo que el problema es porque la tabla alumno no tiene el campo
id
como pk yo estoy usando un numero de identificacion personal… estoy
100%
seguro que es eso…

vaya que metida de pata

El día 22 de julio de 2008 21:45, Manuel P. <
[email protected]> escribió:

No soy el que ha hecho la pregunta, pero muchas gracias Daniel por
dedicar
tu tiempo a explicar las cosas con tanto detalle.
En serio, muchas gracias

Un saludo

El día 22 de julio de 2008 8:58, Daniel R. Troitiño <
[email protected]> escribió:

muchas gracias Daniel por tan buena explicacion pero te informo algunas
cosas:

  1. El password lo estoy creando en el controller porque despues que
    incluyo
    el usuario y el alumno le envio un email al alumno donde le indico su
    password (el email lo envio con el ActionMailer) por eso no hice lo del
    password en el modelo

  2. Lo del validates_confirmation_of :password eso lo usa el plugin
    restful_authentication y necesito tenerlo en el modelo debido a que como
    usuario administrador tengo que crear cuentas de usuario para los
    profesores
    y directores de cada materia por lo tanto lo tengo que dejar en el
    modelo de
    user estimado amigo.

  3. Lo de las relaciones belongs_to y has_one me estoy enterando de eso y
    voy
    a implementarlo inmediatamente. Muchisimas Gracias…

El día 23 de julio de 2008 2:59, Andrés gutiérrez
[email protected]
escribió:

No soy el que ha hecho la pregunta, pero muchas gracias Daniel por dedicar
tu tiempo a explicar las cosas con tanto detalle.
En serio, muchas gracias

Un saludo

Para crear una relación 1-a-1 en Rails, en un modelo debes utilizar
“belongs_to” y en el otro “has_one”. El modelo que posea la clave
foranea (en tu caso Alumno, ya que tiene user_id) debe tener
“belongs_to :user” y en User “has_one :alumno”.

Unas cuantas recomendaciones viendo tú código:

Parece que tienes un “validates_confirmation_of :password” en tu
modelo User. Si eres tú mismo el que proporciona el password al
usuario no debería ser necesario tener un “validates_confirmation_of
:password” en el modelo.

Al quitar esta validación deberías utilizar “attr_protected :password”.

Lo último sobre password sería que debes generarlo en el modelo, en un
filtro “before_create”, no en el controlador.

Aprende a utilizar “create”, que guarda el registro directamente y
devuelve el registro introducido en la base de datos, ahorrandose un
new/save/find.

Los campos “created_at”, “updated_at”, “created_on” y “updated_on” los
actualiza automáticamente Rails, no hace falta que los asignes.

Sobre el campo “status”, si los usuarios siempre se crean con ese
status debería también situarse en un “before_create”, no es necesario
que el controlador conozca estos detalles del modelo. Aunque es cierto
que no hay solución para todo en el caso de los campos con valores por
defecto.

Y finalmente, aprende a utilizar las asociaciones y sus métodos
asociados, es mucho más sencillo utilizar “@user.create_alumno(…)”,
que Alumno.new(…, :user_id => @user.id)". También esto se aplicaría
al utilizar “grupousuario_id” en la creación del usuario, supongo que
en ese caso buscas el grupo de alumnos o algo similar y quieres añadir
el usuario a él.

Al final mí código sería más o menos este:

user.rb

class User < ActiveRecord::Base
attr_protected :password
before_create :generate_password
before_create :assign_status
has_one :alumno
belongs_to :grupousuario
private
def generate_password
self.password = (100000 + rand(899999)).to_s
end
def assign_status
self.status = ‘A’
end
end

alumno.rb

class Alumno < ActiveRecord::Base
belongs_to :user
end

grupousuarios.rb

class Grupousuarios < ActiveRecord::Base
has_many :user
def alumnos
find(1) # el grupo de alumnos tiene ID=1
end
end

en el controlador

@alumnos = Grupousuarios.alumnos

Creamos y salvamos el nuevo usuario

@user = @alumnos.create_user(
:login => params[:suscripcione][:login],
:denusu => params[:suscripcione][:nombre],
:email => params[:suscripcione][:login])

Solamente creamos el nuevo alumnos (tendrias que hacer un

@alumno.save).
@alumno = @user.build_alumno(
:nombre => params[:suscripcione][:nombre],
:apellido => params[:suscripcione][:apellido],
:sexo => params[:suscripcione][:sexo])

Por supuesto falta toda la gestión de los errores que pudiesen suceder.

Se podría ir incluso un poco más lejos si consideramos que es tarea de
la clase alumno crear su usuario asociado, cosa que simplificaría el
código del controlador a una única línea, y no necesitaría de la
“traducción” entre los campos del formulario y los de tus modelos.

Suerte.

2008/7/22 Manuel P. [email protected]:

2008/7/22 Manuel P. [email protected]:

muchas gracias Daniel por tan buena explicacion pero te informo algunas
cosas:

  1. El password lo estoy creando en el controller porque despues que incluyo
    el usuario y el alumno le envio un email al alumno donde le indico su
    password (el email lo envio con el ActionMailer) por eso no hice lo del
    password en el modelo

Al menos justo después de crear el usuario, cuando acabas de
establecer el password “en claro”, puedes acceder a su valor con
@user.password, por lo que no tendrías problemas en mandar un correo
con su valor si no pierdes esa instancia del usuario.

  1. Lo del validates_confirmation_of :password eso lo usa el plugin
    restful_authentication y necesito tenerlo en el modelo debido a que como
    usuario administrador tengo que crear cuentas de usuario para los profesores
    y directores de cada materia por lo tanto lo tengo que dejar en el modelo de
    user estimado amigo.

Si permites que los profesores y los directores se registren
introduciendo ellos mismos su password y su confirmación, quizá sería
más recomendable la solución que comentaba al final de mi otro
mensaje, es decir, crear un Alumno y que este se encarge de crear el
usuario asociado, crear un Profesor y que cree el usuario asociado. De
esa forma puedes poner el validates_confirmation_of en los profesores
y los directores, pero no en los alumnos, que es en realidad tu
intención. Será más trabajo, pero el código será mucho más claro.

Suerte.