Каковы рельсы, чтобы получить доступ к предыдущей записи в серии?
-
29-09-2019 - |
Вопрос
Скажем, у меня есть Statement
модель, которая has_many :months
. Отказ Всегда есть 12 месяцев, связанных с заявлением, но первый месяц может варьироваться (Например, месяцы = [март, апрель, май ... Январь, февраль])
Учитывая определенный месяц, какой способ MVC найти предыдущий месяц?
Я получаю доступ к нему через 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)
Должен ли я иметь previous_month_id
столбец в моей базе данных? Как бы вы реализовали эту функциональность? Я использую рельсы 2.3.x
.
Решение
Я бы определил это на 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
. Отказ Это должно работать даже на неспасенных записях.
Другие советы
Как добавляются эти месяцы? Если они добавляются отдельно в хронологическом порядке месяцев, вы можете просто сделать то, что у вас есть, но вы должны определить порядок в отношениях.
#statement.rb
has_many :months, :order => 'created_at ASC'
Если они добавлены другим способом, вам, возможно, придется подумать о том, чтобы иметь столбец заказа и использовать ACTS_AS_LIST Поддерживать заказ.
Чтобы сделать это по пути 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