如何解决Ruby on Rails:对Form Object的验证不起作用
对Form Object的验证不起作用,我的代码有什么问题?
请阅读已发布的两个案例。第一种情况可以进行验证,第二种情况没有。
案例1
#Profile模型:
class Profile < ApplicationRecord
belongs_to :profileable,polymorphic: true
validates_presence_of :age
validates :age,numericality: { greater_than_or_equal_to: 0,only_integer: true,:allow_blank => true
}
end
从控制台进行的验证测试:
p= Profile.new => #<Profile id: nil,age: nil>
p.age = "string" => "string"
p.save => False
p.errors.full_messages
=> ["Profileable must exist","Age is not a number"]
Profile.create(age:"string").errors.full_messages
=> ["Profileable must exist","Age is not a number"]
直接在模型上进行验证
案例2
#Form对象注册:配置文件:
module Registration
class Profile
include ActiveModel::Model
validates_presence_of :age
validates :age,:allow_blank => true
}
attr_reader :user
delegate :age,:age=,to: :profile
def persisted?
false
end
def user
@user ||= User.new
end
def teacher
@teacher ||= user.build_teacher
end
def profile
@profile ||= teacher.build_profile
end
def save
if valid?
profile.save!
true
else
false
end
end
def submit(params)
profile.attributes = params.slice(:age)
if valid?
profile.save!
end
self
end
def self.model_name
ActiveModel::Name.new(self,nil,"User")
end
def initialize(user=nil,attributes={})
@user = user
end
end
end
#Profile模型:
class Profile < ApplicationRecord
belongs_to :profileable,polymorphic: true
end
从控制台对表单对象进行的验证测试不起作用
a=Registration::Profile.new(User.first)
a.age = "string"
a.save => true
a.errors.full_messages
=> []
解决方法
它返回0
是因为它将age
访问器委托给profile
模型。进行设置时,它会将其传递到基础配置文件,该配置文件会跟踪您设置的值(在profile.attributes_before_type_cast
中),但是在调用它上的age
getter时(委托者会这样做) ),它返回类型转换值(在profile.attributes
中)
p = Profile.new age: "omg"
p.attributes_before_type_cast # => {"id"=>nil,"user_id"=>nil,"age"=>"omg"}
p.attributes # => {"id"=>nil,"age"=>0}
p.age # => 0
我修改了您的示例以将属性存储在Registration::Profile
实例上,并仅在通过活动模型的验证后才将其复制。有多种方法可以执行此操作,但是我使用ActiveModel::Attributes
来执行此操作,因此它的行为类似于ActiveRecord
,因为这可能是最熟悉和兼容的。
现在,您无需将age
委派给配置文件,而是使用attribute :age
对其进行了声明。如果您不需要,则不必使用它们,但您不想将其存储在基础配置文件对象上(例如,如果需要,可以使用attr_accessor
,但同时也可以必须在保存基础配置文件之前手动构建您传递的哈希值。
这是我的版本:
# Setup a database to test it with
require 'active_record'
ActiveRecord::Base.establish_connection adapter: 'sqlite3',database: ':memory:'
ActiveRecord::Schema.define do
self.verbose = false
create_table :users do |t|
t.string :name
end
create_table :profiles do |t|
t.integer :user_id
t.integer :age
end
end
# The underlying models
User = Class.new(ActiveRecord::Base) { has_one :profile }
Profile = Class.new(ActiveRecord::Base) { belongs_to :user }
# The wrapping model
module Registration
class Profile
attr_reader :user,:profile
include ActiveModel::Attributes
attribute :age
include ActiveModel::Model
validates_presence_of :age
validates :age,numericality: { greater_than_or_equal_to: 0,only_integer: true,allow_blank: true }
def initialize(user)
@user = user
@profile = user.profile || user.build_profile
# to set @attributes
super()
# start with the profile's current attributes
self.attributes = profile.attributes.slice(*@attributes.keys)
end
def save
return false unless valid?
profile.attributes = attributes # copy our attributes to the underlying model
profile.save! # we expect it to save,so explode if not
end
end
end
u = User.create!
p = Registration::Profile.new(u)
# Invalid example
p.age = "string"
p.save # => false
p.errors.full_messages # => ["Age is not a number"]
p.age # => "string"
p.profile.age # => nil
p.profile.persisted? # => false
# Valid example
p.age = "123"
p.save # => true
p.errors.full_messages # => []
p.age # => "123"
p.profile.age # => 123
p.profile.persisted? # => true
# Initialize with an existing profile
Registration::Profile.new(u).age # => 123
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。