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.

¿Fue útil?

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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top