1

假设我有一个Statement模型,其中has_many :months. 一个语句总是有 12 个月,但第一个月可能会有所不同(例如,月份 = [Mar, Apr, May...Jan, Feb])

给定某个月份,找到上个月的 MVC 方法是什么?

我发现自己通过statementwhich 感觉很脏来访问它:

# 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)

我应该在我的数据库中有一个previous_month_id列吗?您将如何实现此功能?我正在使用 Rails 2.3.x

4

3 回答 3

1

我会在Month模型上定义它以减少往返。

# 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

这样你就可以得到june.previous。这甚至应该适用于未保存的记录。

于 2010-11-07T21:08:20.257 回答
0

这些月份是如何添加的?如果它们按月份的时间顺序分别添加,那么您可以简单地做您所拥有的,但您应该定义关系中的顺序。

#statement.rb

has_many :months, :order => 'created_at ASC'

如果以其他方式添加它们,那么您可能需要考虑拥有一个订单列并使用acts_as_list来维护订单。

于 2010-11-07T20:54:59.647 回答
0

要以 MVC 方式做到这一点,我可能会将这个逻辑推到“拥有”语句的东西上。毕竟,陈述通常属于某物。不过,在阅读评论后,听起来这是一个继承的项目。如果不是,你必须问为什么你会有一个“几个月”的关系,当声明有一个created_at你可以绑定的列时?这是我想出的,它可能对你没有帮助。尽管至少要结帐Date::MONTHNAMES,但这听起来可能对您有所帮助。

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
于 2010-11-24T02:56:49.973 回答