Forum: Rails-ES Relación has_one y has_many sobre la misma clase

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Carlos B. (Guest)
on 2009-05-06 22:01
Tengo los siguientes modelos:

# Table name: seasons
#
#  id           :integer         not null, primary key
#  league_id    :integer         not null
#  date         :integer         not null
#  actual_round :integer         default(0), not null
#  created_at   :datetime
#  updated_at   :datetime
#

class Season < ActiveRecord::Base
  has_many :rounds, :dependent => :destroy
end

# Table name: rounds
#
#  id           :integer         not null, primary key
#  season_id    :integer         not null
#  round_number :integer         not null
#  created_at   :datetime
#  updated_at   :datetime
#

class Rounds < ActiveRecord:Base
  belongs_to :season
end

El caso es que actual_round apunta a una instancia de round para saber
cual es la jornada actual de la temporada, me gustaría saber si es
posible establecer también una relación has_one en season hacia rounds a
través del campo actual_round.

Gracias.
Fernando C. (Guest)
on 2009-05-06 22:27
Carlos Belizón wrote:
> El caso es que actual_round apunta a una instancia de round para saber
> cual es la jornada actual de la temporada, me gustaría saber si es
> posible establecer también una relación has_one en season hacia rounds a
> través del campo actual_round.
>

Fácil:

class Season < ActiveRecord::Base
  has_many :rounds, :dependent => :destroy
  has_one :round_actual, :foreign_key => 'actual_round'
end


Y para acceder:

  my_season.rounds
  my_season.round_actual

fíjate y no pongas has_one :actual_round , porque si no rails no podrá
saber si te refieres al campo o al objeto, y te dará problemas.

s2
Carlos B. (Guest)
on 2009-05-07 18:22
Fernando C. wrote:
> Carlos Belizón wrote:
>> El caso es que actual_round apunta a una instancia de round para saber
>> cual es la jornada actual de la temporada, me gustaría saber si es
>> posible establecer también una relación has_one en season hacia rounds a
>> través del campo actual_round.
>>
>
> Fácil:
>
> class Season < ActiveRecord::Base
>   has_many :rounds, :dependent => :destroy
>   has_one :round_actual, :foreign_key => 'actual_round'
> end
>
>
> Y para acceder:
>
>   my_season.rounds
>   my_season.round_actual
>
> fíjate y no pongas has_one :actual_round , porque si no rails no podrá
> saber si te refieres al campo o al objeto, y te dará problemas.
>
> s2

Cuando intento acceder a my_season.round_actual me dá el siguiente
error:

uninitialized constant Season::RoundActual

¿Qué estaré haciendo mal?
Carlos B. (Guest)
on 2009-05-07 19:16
Bueno, quizás no me expliqué todo lo bien que debía, vuelvo a explicarme
de forma más extensa:

Tengo una clase llamada Season que está relacionada con Round en una
relación de este tipo:

class Season < ActiveRecord::Base
  has_many :rounds
end

class Round < ActiveRecord::Base
  belongs_to :season
end

Esa relación funciona perfectamente.

Dentro del modelo season tengo un campo llamado actual_round el cuál
guarda el id de una Round (de la jornada actual del campeonato vamos), y
resulta que una Season sólo puede tener una Round como jornada actual.

Si hago esto:

class Season < ActiveRecord::Base
  has_many :rounds
  has_one :round_actual, :foreign_key => 'actual_round'
end

class Round < ActiveRecord:::Base
  belongs_to :season
end

Cuando hago my_season.round_actual recibo el error siguiente:

uninitialized constant Season::RoundActual

¿Es realmente posible hacer lo que estoy haciendo o no?
Manuel González Noriega (Guest)
on 2009-05-07 20:07
(Received via mailing list)
2009/5/7 Carlos Belizón <removed_email_address@domain.invalid>

>
Si el campo lo guardas en Season, no te puede funcionar como clave
foránea
en Round, que es lo que tú estás diciendo

Tal como lo tienes montado, la jornada actual la tienes en

current_round =
@current_season.rounds.find(@current_season.actual_round)

que lo puedes pasar a un método de Season

# season.rb
class Season < ActiveRecord::Base
 has_many :rounds

 def current_round
  rounds.find(actual_round)
 end

end

@season.current_round ya teda la actual



- Por cierto, "actual" en inglés, si no me equivoco, es más bien
"verdadera". La actual sería "current" or "present"

- Supongo que es equivalente y va en gustos, pero yo preferiria guardar
un
booleano "current" en Round y simplemente asegurarme de que se pone y se
quita correctamente. Así puedes usar un named_scope :current

Y por cierto, en algún momento, cambia las claves foráneas para que
acaben
en "_id", se entiende todo mucho mejor :)


Post Data

Como bien dicen mis compañeros, también puedes poner un belongs_to
:current_round, :class_name => 'Round', :foreign_key =>  'actual_round'
en
Seson. De forma que también podrías hacer @current_season.current_round,
pero nos parece semánticamente raruno
Fernando C. (Guest)
on 2009-05-07 22:07
Manuel González Noriega wrote:
> 2009/5/7 Carlos Belizón <removed_email_address@domain.invalid>

> Como bien dicen mis compañeros, también puedes poner un belongs_to
> :current_round, :class_name => 'Round', :foreign_key =>  'actual_round'
> en
> Seson. De forma que también podrías hacer @current_season.current_round,
> pero nos parece semánticamente raruno

Oooops!! esto es exactamente lo que yo quería decir, pero me había
dejado el :class_name => 'Round', y claro... no funcionaba!!

A mí no me parece semánticamente raruno; a mí me encanta... y de hecho,
lo uso. Pero eso son gustos personales... aunque desde luego, es más
corto de escribir y más eficiente a nivel BBDD que
@current_season.rounds.find(@current_season.actual_round)


s2
Carlos B. (Guest)
on 2009-05-07 22:49
Manuel González Noriega wrote:
> 2009/5/7 Carlos Belizón <removed_email_address@domain.invalid>
>
>>
> Si el campo lo guardas en Season, no te puede funcionar como clave
> foránea
> en Round, que es lo que tú estás diciendo
>
> Tal como lo tienes montado, la jornada actual la tienes en
>
> current_round =
> @current_season.rounds.find(@current_season.actual_round)
>
> que lo puedes pasar a un método de Season
>
> # season.rb
> class Season < ActiveRecord::Base
>  has_many :rounds
>
>  def current_round
>   rounds.find(actual_round)
>  end
>
> end
>
> @season.current_round ya teda la actual
>

He optado por implementar esta opción y otro método así:

def current_round=(other)
    actual_round = other.id
end
>
> - Por cierto, "actual" en inglés, si no me equivoco, es más bien
> "verdadera". La actual sería "current" or "present"

Toda la razón, esto me pasa por no tener mucha idea de inglés :).
>
> - Supongo que es equivalente y va en gustos, pero yo preferiria guardar
> un
> booleano "current" en Round y simplemente asegurarme de que se pone y se
> quita correctamente. Así puedes usar un named_scope :current

Pero es tener un campo replicado por todas partes (mala normalización) y
el problema es que esta aplicación es de PFC y como que los profesores
de BBDD se ponen muy pejigueras.

> Y por cierto, en algún momento, cambia las claves foráneas para que
> acaben
> en "_id", se entiende todo mucho mejor :)
>

El problema es que en este caso he ido cambiándolo sobre la marcha :).

> Post Data
>
> Como bien dicen mis compañeros, también puedes poner un belongs_to
> :current_round, :class_name => 'Round', :foreign_key =>  'actual_round'
> en
> Seson. De forma que también podrías hacer @current_season.current_round,
> pero nos parece semánticamente raruno


Eso tiene un problema y es que cuando se implementa hace un select en la
tabla rounds buscando un actual_round cosa que no existe en dicha tabla
:).

Gracias a todos ;).
Manuel González Noriega (Guest)
on 2009-05-08 01:20
(Received via mailing list)
2009/5/7 Fernando C. <removed_email_address@domain.invalid>

> dejado el :class_name => 'Round', y claro... no funcionaba!!
Pero tú decías ponerlo como has_one, no? El problema así es que buscaría
la
fk en la tabla 'rounds' y está en 'seasons'

>
>
> A mí no me parece semánticamente raruno; a mí me encanta... y de hecho,
> lo uso. Pero eso son gustos personales... aunque desde luego, es más
> corto de escribir y más eficiente a nivel BBDD que
> @current_season.rounds.find(@current_season.actual_round)
>


No tengo problema con el has_one, pero hacer ahí que Temporada sea "hija
de"
o "pertenezca a" Jornada, me parece contraintuitivo al invertir la
relación.

En todo caso, sí que es más corto que el find con scope, pero por eso
recomendaba meterlo en un método :)
Manuel González Noriega (Guest)
on 2009-05-08 01:24
(Received via mailing list)
2009/5/7 Carlos Belizón <removed_email_address@domain.invalid>

>
Mmmmm, confieso que no entiendo, un campo booleano en la tabla Rounds
¿rompe
la normalización? Equivale a cualquier campo "active", "featured", o
similar
en otra tabla.


> Eso tiene un problema y es que cuando se implementa hace un select en la
> tabla rounds buscando un actual_round cosa que no existe en dicha tabla
> :).
>
>
Si el belongs_to está en Season, no debería esperar el fk en la tabla
"rounds"
Carlos B. (Guest)
on 2009-05-08 03:08
Manuel González Noriega wrote:
> Mmmmm, confieso que no entiendo, un campo booleano en la tabla Rounds
> ¿rompe
> la normalización? Equivale a cualquier campo "active", "featured", o
> similar
> en otra tabla.

Vale, quizás un flag no sea realmente no normalizar un dato, pero es un
dato repetido en cada jornada que veo bastante innecesario (vamos mi
tutor me ha recomendado quitarlo para que no me pongan pegas) ya que con
un simple "puntero" a la jornada actual solucionas el problema con el
consecuente ahorro de espacio en la BD.


> Si el belongs_to está en Season, no debería esperar el fk en la tabla
> "rounds"

Probaré eso, para ver como funciona y te cuento :).
This topic is locked and can not be replied to.