2010-01-18 24 views
6

Tengo los siguientes tres modelos: Usuario, Proyecto y Asignación.Especificación de la clave foránea en una relación has_many: through

A Usuario has_many Proyectos a través de una asignación. Sin embargo, Asignación realmente tiene dos claves foráneas que se relacionan con un Usuario: user_id (que representa al usuario al que se le asignó el proyecto) y completer_id (representando al usuario que completó el proyecto).

A menudo, user_id y completer_id serán los mismos (si el usuario que se le asignó el proyecto lo completa). Sin embargo, si otro usuario lo completa, user_id y completer_id serán diferentes.

En mi modelo de usuario, Tengo el siguiente:

class User < ActiveRecord::Base 
    has_many :assignments 
    has_many :incomplete_assignments, :class_name => 'Assignment', 
    :conditions => 'completer_id IS NULL' 
    has_many :completed_assignments, :class_name => 'Assignment', 
    :foreign_key => 'completer_id' 

    # this is the important one 
    has_many :incomplete_projects, 
    :through  => :assignments, 
    :source  => :project, 
    :conditions => 'completer_id IS NULL' 
end 

me gustaría hacer otra asociación, llamada :completed_projects, que utiliza completer_id como la clave externa para el usuario en el modelo :through, en lugar de :user_id . ¿Es posible hacer esto?

Y, como un aparte, soy consciente de la opción :foreign_key. Sin embargo, esta opción se ignora al usar :through, por lo que me gustaría saber si hay una manera de hacerlo sin ella.

Finalmente, debo mencionar que estoy abierto a otros diseños, si no se puede hacer de esta manera y alguien puede pensar en una mejor manera.

+4

Bienvenido a tratar de hacer algo medianamente complejo con ActiveRecord. :) – hobodave

Respuesta

3

Siempre se puede utilizar SQL para la selección si ActiveRecord no puede expresar fácilmente la relación de la caja:

has_many :completed_projects, 
:class_name => "Project", 
:finder_sql => 'SELECT p.* FROM projects p ' + 
    'INNER JOIN assignments a ON p.id=a.project_id ' + 
    'INNER JOIN users u on u.id=a.completer_id ' + 
    'WHERE u.id=#{id}' 
+0

Por lo que puedo decir, esta es la única manera de hacerlo. Muchas gracias por esto. – jakeboxer

+0

desafortunadamente, usando: finder_sql rompe el encadenamiento. 'user.completed_projects.limit (2)' no funcionará. –

2

¿Tiene otros metadatos en su tabla de asignaciones?

Si no, simplemente usaría habtm y agregaría el ícono_completo a la tabla de proyectos, de todos modos, tiene sentido vivir allí.

Si necesita/desea utilizar has_many: a través de usted podría buscar en el uso named_scopes (versión rieles permite) por lo que se podría decir user.projects.completed y user.projects.incomplete

Cuestiones relacionadas