Has_many :through y belongs_to

Escribo porque hay una cosa que no tengo del todo claro, y me
gustaríapreguntar sobre ello. Tengo 3 modelos con distintas relaciones tal y
como describo a
continuación:

class City < ActiveRecord::Base
has_many :people
end

class Person < ActiveRecord::Base
belongs_to :city
end

class User < ActiveRecord::Base
belongs_to :city
has_many :people, :through => :city, :class_name => ‘Person’
end

El problema lo tengo accediendo a un User::people. Si intento hacer un
User.find(:first).people obtengo un error, que puede verse que es por un
fallo en el SQL.

User.find(:first).people
ActiveRecord::StatementInvalid: Mysql::Error: Unknown column
‘cities.city_id’ in ‘where clause’: SELECT people.* FROM people INNER
JOIN cities ON people.city_i d = cities.id WHERE ((cities.city_id =
1))

Por lo que veo no soy el único, y realmente no tengo muy claro si
debería funcionar. Entiendo que si no estuviera permitido ese has_many
el error debería darse anteriormente. He probado con algunas
combinaciones de :class_name y :source sin ningún éxito, y el uso de
:foreign_key tampoco arregla nada. Según la
documentación"You can only use a :through query through a belongs_to or has_many
association on the join model." pero no consigo echarlo a andar.

La solución de usar :finder_sql tampoco me apasiona porque limita mucho
la relación (no pueden usarse los métodos automágicos find[_all]_by.
¿Alguna pista de si puedo hacer algo para solucionarlo o si debo buscar
otro diseño en las relaciones?

Muchas gracias por adelantado.

On Sat, Dec 15, 2007 at 09:36:58PM +0100, Pablo Martínez Schroder wrote:

class User < ActiveRecord::Base
belongs_to :city
has_many :people, :through => :city, :class_name => ‘Person’
end

Por error de corregir el copy&paste ha aparecido el :class_name que no
sirve para nada (con :through no se usa, para eso está :source).

He estado ojeando el código de ActiveRecord pero la verdad es que no he
conseguido encontrar nada que pueda ayudarme, ya que no estoy
familiarizado con el código de esas librerías y gran parte de las pistas
parecen ir para relaciones polimórficas.

Por lo que he visto hasta ahora, me temo que hacer un “has_many
:loquesea, :trough => :relación” solo es posible cuando relacion es
también un has_many, no un belongs_to :-/, así que parece que ahí se
acaba mi intención de usar :conditions => ‘blabla’

Un saludo.

On 12/15/07, Pablo Martínez Schroder [email protected] wrote:

‘cities.city_id’ in ‘where clause’: SELECT people.* FROM people INNER
La solución de usar :finder_sql tampoco me apasiona porque limita mucho
la relación (no pueden usarse los métodos automágicos find[_all]_by.
¿Alguna pista de si puedo hacer algo para solucionarlo o si debo buscar
otro diseño en las relaciones?

Y por que no usar?:

User.find(:first).city.people

Y si queres un metodo en User directamente:
def people
city.nil? [] : city.people
end

On 12/16/07, Emilio T. [email protected] wrote:

end
ActiveRecord::StatementInvalid: Mysql::Error: Unknown column

def people
city.nil? [] : city.people
^^^^^^^^^^^^^^^^^^^^^^^^
Upsss, typo (me comi un ?):

city.nil? ? [] : city.people

On Sun, Dec 16, 2007 at 01:42:47PM -0300, Emilio T. wrote:

Y por que no usar?:

User.find(:first).city.people

Esta solución siempre está ahí, y seguramente será lo que tenga que
hacer, pero me parecía interesante poder definir relaciones como

has_many :women, :through => :city, :source => :people, :conditions
=> “gender = ‘F’”

Y si queres un metodo en User directamente:
def people
city.nil? [] : city.people
end

El problema es que el método devuelve un Array y no se puede hacer
find_by_name y ese tipo de cosas.

Realmente no es un problema tan grave, sólo pensaba que se puede hacer
algo más interesante, y que la relación parece funcionar y sólo es un
fallo en el WHERE del SQL (el INNER JOIN está bien) igual se puede
corregir de alguna forma.

Un saludo.

On Sat, Dec 15, 2007 at 11:47:02PM +0100, Pablo Martínez Schroder wrote:

class User < ActiveRecord::Base
belongs_to :city
has_many :people, :through => :city
end

Por lo que he visto hasta ahora, me temo que hacer un “has_many
:loquesea, :trough => :relación” solo es posible cuando relacion es
también un has_many, no un belongs_to :-/, así que parece que ahí se
acaba mi intención de usar :conditions => ‘blabla’

Me respondo yo mismo. Ya vi en su momento que el comportamiento de Rails
es así, de hecho incluso alguien ha enviado un parche[1] que por alguna
razón no es aceptado. Veremos si se incluye en alguna versión, la verdad
creo que es algo bastante razonable y algo que uno esperaría que
funcionase, ya que las soluciones alternativas (como los delegate)
sólosirven para casos triviales.

[1] http://dev.rubyonrails.org/ticket/9851