Cuál es la forma rieles para acceder al registro anterior en una serie?
-
29-09-2019 - |
Pregunta
Decir que tengo un modelo Statement
, que has_many :months
. Siempre hay 12 meses asociados con una declaración, pero el primer mes puede variar (por ejemplo, meses = [marzo, abril, mayo ... enero, febrero])
Dado un determinado mes, ¿cuál es la forma MVC para encontrar el mes anterior?
Me encuentro acceder a él a través de la cual se siente sucia statement
:
# statement.rb
has_many :months
def previous_month(month)
if months.index(month) == 0
return nil
else
return months[months.index(month) - 1]
end
end
# blergh
prev_month = month.statement.previous_month(month)
¿Debería haber una columna previous_month_id
en mi base de datos? ¿Cómo se decide implementar esta funcionalidad? Estoy usando Rails 2.3.x
.
Solución
Yo lo definiría en el modelo Month
con espalda corte en las idas y vueltas.
# month.rb
class Month < ActiveRecord::Base
belongs_to :statement, :include => :months
def previous
return nil if self.index == 0
find_or_create_by_index_and_statement_id(self.index - 1, self.statement.id)
end
def index
statement.months.index self
end
end
por lo que se puede obtener june.previous
. Este trabajo debe incluso en los registros guardados.
Otros consejos
¿Cómo se añaden estos meses? Si están añaden por separado en el orden cronológico de los meses, entonces puede simplemente hacer lo que tienes, sino que debe definir el orden en la relación.
#statement.rb
has_many :months, :order => 'created_at ASC'
Si están añaden alguna otra manera, entonces puede que tenga que pensar en tener una columna de orden y utilizando acts_as_list para mantener el orden.
Para hacer esto de la manera MVC, probablemente empujar esta lógica en lo que 'posee' las declaraciones. Después de todo una declaración por lo general pertenece a algo. Después de leer los comentarios embargo, parece que este es un proyecto heredado. Si no tienes que preguntar ¿por qué tener una relación '' meses, cuando la instrucción tiene una columna created_at
se puede atar en? Esto es lo que ocurrió con, puede que no sea útil para usted. Aunque Date::MONTHNAMES
tareas pendientes de pago por lo menos suena como que podría ser útil para usted.
describe User do
before(:each) do
@user = User.create!
end
it "should know about months" do
Statement.create(:user => @user)
@user.statements.last.month_name.should == "November"
end
it "should report last months statement as nil when there is no statement" do
@user.last_months_statement.should be_nil
end
it "should report last months statement as nil if there is only one for this month" do
Statement.create(:user => @user)
@user.last_months_statement.should be_nil
end
it "should report a statement from the previous month if there is one" do
target = Statement.create(:user => @user, :created_at => 1.month.ago)
Statement.create(:user => @user)
@user.last_months_statement.should == target
end
it "should report last months statement if there a several" do
Statement.create(:user => @user, :created_at => 1.month.ago)
Statement.create(:user => @user)
Statement.create(:user => @user, :created_at => 2.months.ago)
@user.last_months_statement.month_name.should == "October"
end
end
class User < ActiveRecord::Base
has_many :statements, :order => "created_at"
def last_months_statement
if statements.size <= 1 || statements.last.created_at.month < Time.now.month
nil
else
index = statements.index(statements.last)
statements[index - 1]
end
end
end
class Statement < ActiveRecord::Base
belongs_to :user
def month
created_at.month
end
def month_name
Date::MONTHNAMES[created_at.month]
end
end