我有两个模型,它们都具有相同的状态(草稿、实时、非活动)。我喜欢通过值对象干燥我的代码的想法。我创建了以下代码:
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'
我编写此验证的更好方法是什么?