1

我有两个模型,它们都具有相同的状态(草稿、实时、非活动)。我喜欢通过值对象干燥我的代码的想法。我创建了以下代码:

class CurrentStatus
  STATUSES = %w"DRAFT LIVE INACTIVE"
  attr_reader :status

  def initialize(status)
    stringed_status = status.to_s
    if STATUSES.include?(stringed_status)
      @status = stringed_status
    else
      raise "Invalid state for object Status"
    end
  end
end

在模型中:

class Interest < ActiveRecord::Base
  composed_of :status, :class_name => 'CurrentStatus', :mapping => %w(status)
  attr_accessible :description, :name, :status

这使我能够成功执行:

[47] pry(main)> i = Interest.new
=> #<Interest id: nil, name: nil, description: nil, created_at: nil, updated_at: nil, status: nil>
[49] pry(main)> i.status = CurrentStatus.new('blech')
RuntimeError: Invalid state for object Status from /app/models/current_status.rb:10:in `initialize'
[50] pry(main)> i.status = CurrentStatus.new('DRAFT')
=> DRAFT
[51] pry(main)> i
=> #<Interest id: nil, name: nil, description: nil, created_at: nil, updated_at: nil, status: "DRAFT">

但不是:

[48] pry(main)> i.status = 'DRAFT'
NoMethodError: undefined method `status' for "DRAFT":String
from ruby-1.9.3-p429/gems/activerecord- 3.2.13/lib/active_record/aggregations.rb:248:in `block (2 levels) in writer_method'

所以当在 InterestsController 我调用新方法时:

  def new
    @interest = Interest.new

并拉起表格:

    <div class="field">
      <%= f.label :status %><br />
      <%= f.select(:status, %w"DRAFT REPORT_ONLY LIVE SUSPENDED" ) %>

我的验证阻止了我:

  Rendered interests/_form.html.erb (70.1ms)
  Rendered interests/new.html.erb within layouts/application (83.0ms)
Completed 500 Internal Server Error in 465ms

RuntimeError - Invalid state for object Status:
  app/models/current_status.rb:10:in `initialize'
  activerecord (3.2.13) lib/active_record/aggregations.rb:229:in `block in reader_method'

我编写此验证的更好方法是什么?

4

2 回答 2

1

感谢您的帮助材料设计师。我也把这个发给了一些朋友。你的回答和他们的回答一样让我成功了。

他们说服我摆脱'composed_of',因为它可能已被弃用。我听取了您的建议并使用了 ActiveModel::Validations。这是最终的工作代码:

这是当前状态:

class CurrentStatus
  include ActiveModel::Validations
  STATUSES = %w"DRAFT LIVE SUSPENDED"
  attr_reader :status

  validates_inclusion_of :status, :in => STATUSES

  def initialize(status)
    @status = status.to_s
  end

  def self.valid_statuses
    STATUSES.to_a
  end

  def self.to_a
    self.valid_statuses
  end

  def to_s
    @status.to_s
  end
end

和兴趣.rb

# == Schema Information
#
# Table name: interests
#
#  id          :integer          not null, primary key
#  name        :string(255)
#  description :text
#  created_at  :datetime         not null
#  updated_at  :datetime         not null
#  status_key  :string(255)
#

class Interest < ActiveRecord::Base
  attr_accessible :description, :name, :status_key, :status

  validate :valid_status

  def status
    return CurrentStatus.new(status_key)
  end

  def status=(value)
    self.status_key = value
  end

  private
  def valid_status
    errors.add(:status_key, "is invalid") unless status.valid?
  end

end

这段代码允许我说Interests.create(status: 'INVALID_STATUS'),系统将在允许通过时阻止保存Interests.create(status: 'LIVE')。谢谢你的帮助!

于 2013-10-09T03:32:52.770 回答
0

Interest我认为使用 ActiveModel 验证更有意义,然后,当尝试保存整个模型时,应该触发这些验证。

class CurrentStatus
  include ActiveModel::Validations

  STATUSES = %w(DRAFT LIVE INACTIVE)
  attr_reader :status

  validates_inclusion_of :status, :in => STATUSES

  def initialize(status)
    stringed_status = status.to_s
    @status = status.to_s
  end
end
于 2013-10-04T07:28:06.140 回答