使用虚拟属性时如何添加错误消息
How to Add an Error Message when using a Virtual Attribute
我有一个日期字段不是必填字段。我正在使用 Chronic 将用户输入字符串格式化为日期字段的有效 rails 格式。如果 Chronic 无法解析日期,我想提出一个错误,使用相应的错误消息和原始输入值呈现编辑视图。目前,如果输入无效日期,则更新成功,但 service_date 字段没有任何更新。
new.html.erb
<%= f.text_field :service_date_text %>
bill.rb
require 'chronic'
class Bill < ActiveRecord::Base
def service_date_text
service_date.try(:strftime, "%m/%d/%Y")
end
def service_date_text=(date)
if date.present?
if Chronic.parse(date)
self.service_date = Chronic.parse(date)
else
self.errors.add(:service_date_text, "invalid date format hello.")
end
else
self.service_date = ''
end
end
end
bills_controller.rb
def update
@bill = current_account.bills.find(params[:id])
if @bill.update_attributes(bill_params)
redirect_to @bill, notice: 'Bill has been successfully updated.'
else
render :edit
end
end
private
def bill_params
params.require(:bill).permit(:description, :notes, :po_number, :service_date_text)
end
我敢打赌问题是 Rails 不希望 setter 方法添加错误。我会让 service_date_text
只是一个 attr_accessor,然后调用一个验证方法来设置 service_date
或添加一个错误。
attr_accessor :service_date_text
validate :service_date_text_format
private
def service_date_text_format
return unless service_date_text # or self.service_date ||= '' and then return
if date = Chronic.parse(date)
self.service_date = date
else
errors.add(:service_date, 'invalid format')
end
end
errors
会在您 运行 valid?
时被清除,而 update_attributes
会。
示例:
irb(main):001:0> album = Album.new
=> #<Album id: nil, name: nil, release_date: nil, rating: nil, genre_id: nil,
artist_id: nil, created_at: nil, updated_at: nil>
irb(main):004:0> album.errors.add :artist, "You've selected Justin Bieber (!!!)"
=> ["You've selected Justin Bieber (!!!)"]
irb(main):006:0> album.errors.messages
=> {:artist=>["You've selected Justin Bieber (!!!)"]}
irb(main):007:0> album.valid?
=> true
irb(main):008:0> album.errors.messages
=> {}
不要滥用设置器,使用适当的验证。例如(未测试):
require 'chronic'
class Bill < ActiveRecord::Base
validate :service_date_validation
def service_date_text
service_date.try(:strftime, "%m/%d/%Y")
end
def service_date_text=(date)
if date.present?
if Chronic.parse(date)
self.service_date = Chronic.parse(date)
else
self.service_date = false
end
else
self.service_date = ''
end
end
private
def service_date_validation
if self.service_date == false
self.errors.add(:service_date_text, "invalid date format hello.")
end
end
end
... 还有一些提供日期验证的 gem,例如:
- https://rubygems.org/gems/validates_timeliness
- https://rubygems.org/gems/date_validator
- https://rubygems.org/gems/rails_validations(免责声明:我是作者)
...以及其他一些...
我有一个日期字段不是必填字段。我正在使用 Chronic 将用户输入字符串格式化为日期字段的有效 rails 格式。如果 Chronic 无法解析日期,我想提出一个错误,使用相应的错误消息和原始输入值呈现编辑视图。目前,如果输入无效日期,则更新成功,但 service_date 字段没有任何更新。
new.html.erb
<%= f.text_field :service_date_text %>
bill.rb
require 'chronic'
class Bill < ActiveRecord::Base
def service_date_text
service_date.try(:strftime, "%m/%d/%Y")
end
def service_date_text=(date)
if date.present?
if Chronic.parse(date)
self.service_date = Chronic.parse(date)
else
self.errors.add(:service_date_text, "invalid date format hello.")
end
else
self.service_date = ''
end
end
end
bills_controller.rb
def update
@bill = current_account.bills.find(params[:id])
if @bill.update_attributes(bill_params)
redirect_to @bill, notice: 'Bill has been successfully updated.'
else
render :edit
end
end
private
def bill_params
params.require(:bill).permit(:description, :notes, :po_number, :service_date_text)
end
我敢打赌问题是 Rails 不希望 setter 方法添加错误。我会让 service_date_text
只是一个 attr_accessor,然后调用一个验证方法来设置 service_date
或添加一个错误。
attr_accessor :service_date_text
validate :service_date_text_format
private
def service_date_text_format
return unless service_date_text # or self.service_date ||= '' and then return
if date = Chronic.parse(date)
self.service_date = date
else
errors.add(:service_date, 'invalid format')
end
end
errors
会在您 运行 valid?
时被清除,而 update_attributes
会。
示例:
irb(main):001:0> album = Album.new
=> #<Album id: nil, name: nil, release_date: nil, rating: nil, genre_id: nil,
artist_id: nil, created_at: nil, updated_at: nil>
irb(main):004:0> album.errors.add :artist, "You've selected Justin Bieber (!!!)"
=> ["You've selected Justin Bieber (!!!)"]
irb(main):006:0> album.errors.messages
=> {:artist=>["You've selected Justin Bieber (!!!)"]}
irb(main):007:0> album.valid?
=> true
irb(main):008:0> album.errors.messages
=> {}
不要滥用设置器,使用适当的验证。例如(未测试):
require 'chronic'
class Bill < ActiveRecord::Base
validate :service_date_validation
def service_date_text
service_date.try(:strftime, "%m/%d/%Y")
end
def service_date_text=(date)
if date.present?
if Chronic.parse(date)
self.service_date = Chronic.parse(date)
else
self.service_date = false
end
else
self.service_date = ''
end
end
private
def service_date_validation
if self.service_date == false
self.errors.add(:service_date_text, "invalid date format hello.")
end
end
end
... 还有一些提供日期验证的 gem,例如:
- https://rubygems.org/gems/validates_timeliness
- https://rubygems.org/gems/date_validator
- https://rubygems.org/gems/rails_validations(免责声明:我是作者)
...以及其他一些...