如何使state_machine块使用默认访问器而不是我的自定义访问器?

时间:2013-02-13 22:43:18

标签: ruby ruby-on-rails-3 state-machine accessor

我正在实施pluginaweek's state_machine gem。我将代码缩小到这一点,这样我就可以更容易地理解这个问题了。我们假设我现在只有一个状态:

class Event < ActiveRecord::Base
  state_machine :status, :initial => :active_offer do
  end

  def status
    'Active Offer'
  end
end

通过播种或浏览器创建新的Event对象时遇到的错误是{:status=>["is invalid"]}

计划是包含所有不同状态的条件,并将自定义字符串返回到视图。整个项目的视图目前使用.status语法,所以我试图顺利安装它。我基于阅读api文档开始了这个解决方案:

http://api.rubyonrails.org/classes/ActiveRecord/Base.html#label-Overwriting+default+accessors

这是我的主要目标:

def status
  if read_attribute(:status) == 'active_offer' && self.start_date > Time.now
    'Active Offer'
  elsif read_attribute(:status) == 'active_offer' && self.start_date < Time.now
    'Expired'
  else read_attribute(:status) == 'cancelled'
    'Cancelled'
  end
end

如何使state_machine块使用普通访问器以获取数据库值?

银弹解决方案:

我的主要问题是访问者覆盖status。当state_machine代码正在运行时,它正在通过我的访问器覆盖读取当前状态,因此返回一个自定义字符串,这是一个无效状态。我不得不使用state_machine:state。我最初没有这样做,因为我已经有了省份等的州attr,所以我将其迁移到:address_state。

1 个答案:

答案 0 :(得分:1)

非常确定您只需要更改定义的名称:

class Event < ActiveRecord::Base
  state_machine :status, :initial => :active_offer do
  end

  def active_offer
    'Active Offer'
  end
end

修改

如果我理解正确,我不确定,我会这样做:

state_machine :status, initial: :active_offer do
  event :expire do
    transition all => :expired
  end
  event :cancel do
    transition all => :cancelled
  end
end

然后,您可以在控制器或其他内容中执行if...语句等,并使用@event.expireif @event.expired等内容进行转换。如果您想要自动化,则需要whenever