Su condición has_one
nunca funcionará en los carriles, por lo que yo sé.
Necesita una explícita has_one
o belongs_to
o has_many por "enlace", en ambas tablas. Entonces, si tiene dos "enlaces", necesita dos has_one
y dos belongs_to
. Así es como funciona.
En segundo lugar, creo que debería reconsiderar sus modelos. La forma en que lo hace, una persona no puede ser el presidente de un club y un empleado, al mismo tiempo. O ser el presidente de dos clubes. Incluso si no los tiene ahora mismo, pueden venir en el futuro; es más fácil mantenerse flexible en este momento.
Una forma flexible de hacerlo es usando un has_many :through
con una tabla intermedia que especifica el rol. En otras palabras:
# The memberships table has a person_id, club_id and role_id, all integers
class Membership < ActiveRecord::Base
belongs_to :club
belongs_to :person
validates_presence_of :role_id
validates_numericality_of :role_id
end
class Club < ActiveRecord::Base
has_many :memberships, :dependent => :delete_all
has_many :people, :through => :memberships
end
class Person < ActiveRecord::Base
has_many :memberships, :dependent => :delete_all
has_many :clubs, :through => :memberships
end
Ahora, suponiendo que los empleados ROLE_ID = 0 significa, ROLE_ID = 1 significa que el presidente, y ROLE_ID = 2 significa vice_president, se puede utilizar de esta manera:
tyler = Person.find(1) # person_id is 1
other = Person.find(2) # person_id is 2
c = Club.find(1) # club_id is 1
tyler.clubs # returns all the clubs this person is "member" of
c.people # returns all the "members" of this club, no matter their role
#make tyler the president of c
tyler.memberships.create(:club_id => 1, :role_id => 1)
#make other the vicepresident of c
#but using c.memberships instead of other.memberships (works both ways)
c.memberships.create(:person_id => 2, :role_id => 1)
#find the (first) president of c
c.memberships.find_by_role_id(1).person
#find the (first) vicepresident of c
c.memberships.find_by_role_id(2).person
#find all the employees of c
c.memberships.find_all_by_role_id(0).collect { |m| m.person }
#find all the clubs of which tyler is president
tyler.memberships.find_all_by_role_id(1).collect { |m| m.club }
Notas adicionales :
- Puede complementar esto con una tabla y un modelo de roles. Los roles tendrían solo un nombre, los roles serían relaciones
have_many
y las membresías serían belong_to
rol.O bien, puede definir métodos en membresías para obtener el nombre del rol (si es 0, devuelve "empleado", si 1, "presidente", etc.
- Puede agregar validaciones en membresías para que no se pueda hacer más de 1 persona presidente de un club determinado o del mismo empleado en el mismo club dos veces. Más adelante, si comienza a obtener "casos excepcionales" en los que una persona necesita estar en dos lugares, deberá adaptar sus validaciones.
Ok, definitivamente parece una mejor estructura. Sin embargo, no estoy seguro de cómo funciona el empleado en esto. La designación de los empleados es realmente independiente si forman parte de un club o no, por lo que no creo que deba ser parte de la membresía. A propósito, ya uso un modelo de Roles para los diferentes roles de empleados que tenemos. Entonces, ¿tal vez en el modelo Person debería haber una asociación con un has_one EmployeeRole y eso daría su tipo de empleado? – adimitri
¡Hola! No estoy seguro de entender lo que quieres decir con "realmente independiente si son parte de un club o no". Si tiene una tabla Roles con roles de empleado, podría agregar 2 más ("presidente" y "vicepresidente") y solo usar una cosa. ¿Por qué quieres separarlos? – kikito
Esta aplicación es para una organización gubernamental estudiantil en un campus universitario. Financian una gran cantidad de clubes que son administrados por estudiantes y tienen 4 puestos en el tablero electrónico (presidente, vicepresidente, secretario tesorero). Los empleados son del gobierno estudiantil y también estudiantes, pero no tiene nada que ver con el club. Entonces, pueden ser parte de una junta electrónica del club y un empleado. – adimitri