我正在创建一个任务管理器,并为'finished'设置了一个布尔属性。当我将'finished'切换为true时,我试图覆盖setter来实现'finished_at'日期。
但是我得到了一些混合的结果。它在浏览器中不起作用,但它可以在我的rspec测试中使用。
请帮帮我。
class TasksController < ApplicationController
# ...
def update
# ..
if @task.update_attributes(params[:task]) # where params[:task][:finished] is true
# ...
end
class Task < ActiveRecord::Base
#...
def finished=(f)
write_attribute :finished, f
write_attribute :finished_at, f == true ? DateTime.now : nil
end
end
# and in rspec i have
describe "when marked as finished" do
before { @task.update_attributes(finished: true) }
its(:finished_at) { should_not be_nil }
its(:finished_at) { should > (DateTime.now - 1.minute) }
describe "and then marked as unfinished" do
before { @task.update_attributes(finished: false) }
its(:finished_at) { should be_nil }
end
end
在浏览器中执行“UPDATE”任务“SET”完成“='t',”updated_at“='2012-10-02 18:55:07.220361'WHERE”任务“。”id“= 17”
并且在rails控制台中我得到了与update_attributes相同的内容。
但是在带有update_attributes的rspec中,我得到“UPDATE”任务“SET”完成“='t',”finished_at“='2012-10-02 18:36:47.725813',”updated_at“=''2012-10- 02 18:36:51.607143'WHERE'任务“。”id“= 1”
所以我使用相同的方法,但它仅在rspec中用于某些共振......
使用最新的rails和最新规范(不是任何rc或beta)。
我不需要编辑。谢谢@Frederick Cheung的暗示。 我注意到我确实喜欢“self [:attr]”而不是“write_attribute”。看起来更好imo。
def finished=(value)
self[:finished] = value
self[:finished_at] = (self.finished? ? Time.now.utc : nil)
end
答案 0 :(得分:1)
您的setter会在传递给update_attributes
时传递值。特别是当这是由表单提交触发时(假设您使用常规rails表单助手)f
实际上将是“0”或“1”,因此与true
的比较将永远是假的。
最简单的方法是在第一次调用finished?
后检查write_attribute
的值,以便rails可以将提交的值转换为true / false。做== true
也很麻烦 - 如果你测试的东西返回一个真实的值而不是实际的真值,这将会破坏(例如=〜字符串在匹配时返回一个整数)
答案 1 :(得分:1)
您可以使用ActiveRecord Dirty Tracking通知此更改。
http://api.rubyonrails.org/classes/ActiveModel/Dirty.html
class Task < ActiveRecord::Base
before_save :toggle_finished_at
def toggle_finished_at
if finished_changed?
before = changes['finished'][0]
after = changes['finished'][1]
# transition from finished => not-finished
if before == true && after == false
self.finished_at = nil
end
# transition from not finished => finished
if before == false && after == true
self.finished_at = Time.now.utc
end
end
end
end
答案 2 :(得分:0)
这是状态机的用例。您调用:finish!
事件(一种方法),该事件被配置为更改状态并执行其他任何操作。