我有两个模型都具有相同的状态(草稿,实时,非活动)。我喜欢通过值对象来干掉我的代码的想法。我创建了以下代码:
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'
对我来说,编写此验证的更好方法是什么?
答案 0 :(得分:1)
感谢您帮助materialdesigner。我也把它发给了一些朋友。你的答案让我和他们一样在那里。
他们说服我摆脱'composed_of',因为这个词可能会被弃用。我接受了你的建议并使用了ActiveModel :: Validations。这是最终的工作代码:
这是CurrentStatus:
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
和Interests.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')
时阻止保存。谢谢你的帮助!
答案 1 :(得分:0)
我认为使用ActiveModel验证更有意义
当整个Interest
模型试图被保存时,应该触发这些。
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