我有一个Post
类,其中title:string
字段
post = Post.create!
#=> Post created
post.title = "foo"
post.save!
# success
post.title = 1
post.save!
# succeeds, but I want it to throw a type mismatch exception
如何获得最后一次保存!抛出类型不匹配?
答案 0 :(得分:3)
这实际上违背了Ruby的全部内容。如果它是一个字符串列,数据库层将负责将该值呈现为字符串并保存它。
Ruby中的类型概念与其他语言不同。通常,如果一个对象支持to_s
,那么它被认为是 string-enough ,这是Duck Typing的基本原则。
如果传入无法呈现为字符串的内容,则会出现异常。例如:
post.title = Post.find(5)
如果您希望确保字段不是数字,则应添加强制执行特定格式的验证。
答案 1 :(得分:2)
已经创建了一个新的gem来帮助validate types in rails和explanatory blog post来回答更多因为它首先创建的“原因”。
使用此库,您的代码很简单:
cat /media/DRIVENAME/BACKUPNAME.tgz.* | tar -x /
当将整数分配给class Post < ActiveRecord::Base
validates_type :title, :string
end
而不是将title
静默地转换为字符串并保存它时,这将抛出异常。
答案 2 :(得分:1)
Ruby是一种鸭子类型的语言,没有类型不匹配。如果对象响应to_s
,Rails将在其上调用to_s
并将其放入字符串字段中。
听起来你真正想要的是验证你放入字段的值的格式(字符串"2"
是一个有效值?),这是validates_format_of
的用途。例如,如果要确保该值至少包含一个非数字字符,则可以执行以下操作:
class Post < ActiveRecord::Base
validates_format_of :title, with: /\D/
end
当然,您可能希望更多地自定义该正则表达式。
如果你真的无法忍受鸭子打字并想确保除了真正的字符串进入该列之外什么都没有,你可以覆盖title=
:
class Post < ActiveRecord::Base
def title=(value)
throw "`title' must be a String" unless value.is_a?(String)
super
end
end
请注意,执行此操作时不会调用此方法。 post[:title] = ...
或post.write_attribute(:title, ...)
,但它应涵盖95%的情况。
答案 3 :(得分:0)
要回答确切的问题,如果要确保只将类String的对象保存到字段中,则应添加以下自定义验证。
validate :must_be_string
def must_be_string
errors.add(:base, 'The field must be String') unless title.class == String
end
答案 4 :(得分:0)
您可以定义自定义验证程序。
validates :title, type: String
然后:
class TypeValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
record.errors.add attribute, (options[:message] || "is not of class #{options[:with]}") unless
value.class == options[:with]
end
end