ruby-on-rails - name - rails references
¿Cuál es la "vía de los rieles" para imponer una asociación has_many pero have-only-one-current? (3)
¿Por qué no solo agrega una columna de fecha y hora llamada activated_at
a su modelo de Phase
? Luego, establezca esto a la hora actual cada vez que desee activar una fase.
En cualquier momento dado, la fase con el último valor de activated_at
es la fase actual, por lo que solo puede obtenerla con @project.phases.order(''activated_at DESC'').first
. Simplemente envuelva esto en un método en Project
y tendrá una representación muy concisa:
# in project.rb
def current_phase
phases.where("activated_at is NOT NULL").order(''activated_at DESC'').first
end
Tengo una aplicación de rieles simple con proyecto y fase de modelos. Un proyecto tiene muchas fases, pero solo en fase puede estar activo (es decir, "actual") a la vez. Todavía quiero que las otras fases sean accesibles, pero la fase actual debe ser el ancla principal de la aplicación. La decisión sobre cómo implementar este requisito tiene implicaciones importantes sobre cómo manejo el acceso al modelo, las validaciones y las vistas / formularios para la actualización de la creación.
Entonces, la pregunta es: ¿Cómo puedo lograr esta asociación "has_many pero have-only-one-current" sin agregar demasiada complejidad? Los objetivos principales son: simplicidad en el acceso de la fase actual + garantizar que no puede haber más de 1 fase activa a la vez.
Naturalmente, tuve algunas ideas y se me ocurrieron tres opciones, que quiero presentar aquí. Cualquier comentario sobre por qué debería elegir una opción sobre la otra (o sugerencia de una solución más simple) sería apreciado:
Primera opción:
[Project] has_many :phases
[Project] has_one :current_phase, :class_name => "Phase", :conditions => { :current => true }
Inconveniente: Tengo una forma anidada para crear proyectos y las fases correspondientes. Parece que no hay una manera fácil de configurar exactamente una de las fases recién creadas como activas
Segunda opción:
[Project] has an attribute "current_phase_id"
[Project] has_many :phases
[Project] belongs_to phase, :foreign_key => "current_phase_id"
Inconveniente: igual que la opción 1, pero tengo otro atributo y una asociación de pertenencia, lo que parece extraño (¿por qué un proyecto debe pertenecer a una de sus fases?)
Tercera Opción:
[Phase] has an attribute "active" (boolean)
[Phase] scope :active, :conditions => { :active => true}
# Access to current phase via: project.phases.active
Inconveniente: tengo que asegurar a través de validaciones que solo hay una fase activa a la vez, lo cual es difícil si se crean / editan múltiples fases al mismo tiempo O durante el cambio de una fase a otra; más: project.phases.active devuelve una matriz, si no me equivoco
Tu ayuda es muy apreciada. ¡Gracias!
Actualizar
Se agregó una recompensa para alentar nuevas opiniones sobre el tema. La recompensa se otorgará a la solución que mejor aborde los objetivos principales expresados anteriormente; o si no se menciona una solución alternativa, a la respuesta que mejor explique por qué debo favorecer una de las opciones dadas sobre la otra. ¡Gracias!
La opción 1 se ve muy nativa. Solo necesita agregar validación para validar si solo hay una fase con current
project_id
current
y project_id
y algún javascript para controlar las casillas de verificación en el lado del cliente.
class Project < AR::Base
has_many :phases
has_one :current_phase, :class_name => "Phase", :conditions => { :current => true }
accepts_nested_attributes_for :phases, :allow_destroy => true
end
class Phase < AR::Base
belongs_to :project
validates :project_id, :uniqueness => {:scope => :current}, :if => proc{ self.current }
end
Por lo tanto, sus puntos de vista:
<%= form_for @project do |f| %>
...
<%= f.fields_for :phases do |phase| %>
<%= phase.text_field :title %> # or whatever
<%= phase.check_box :current, :class => "current_phase" %>
<% end %>
...
<% end %>
Y un pequeño javascript (jQuery en realidad) para desmarcar todas current
casillas de verificación current
pero una en la que hizo clic.
$(document).ready(function(){
$(".current_phase").click(function(){
$(".current_phase").not(this).attr(''checked'', false);
}
})
Una pregunta bien presentada. He luchado con algo muy similar. Lo que obtuve fue similar a su opción 1, pero usando una tabla de unión.
class Project < ActiveRecord::Base
has_many :phases, :through=> :project_phase
has_one :active_project_phase, :class_name => ''ProjectPhase''`
Para configurar exactamente una de las fases recién creadas activas, tengo un poco de código en el controlador que las hace todas inactivas y luego agrega una nueva fase activa si no hay fases o elige una para activar según los parámetros pasados y un montón de reglas No es bonito, pero funciona. Primero probé la opción 3, pero encontré que esto se volvió muy complicado por las razones que describe