这是我的凭证模型:
class Credential < ApplicationRecord
validate :password_or_certificate
enum credential_type: { windows: 1, linux: 2 }
def password_or_certificate
unless user_pass.blank? ^ cert_file_path.blank?
errors.add(:base, "Please provide a password or a certificate, not both.")
end
end
end
我正在检查控制器中的证书,并在控制器中设置错误,如下所示:
def create
attachment = params[:credential][:cert_file_path]
cert_file_path = Rails.root.join('private', 'certificates', attachment.original_filename) if attachment.present?
@credential = Credential.new(credential_params)
@credential.cert_file_path = cert_file_path
if @credential.valid? && cert_file_path.present?
cert_error_msg = 'Certificate is not valid'
fm = FileMagic.new(FileMagic::MAGIC_MIME)
file_path = attachment.path
if fm.file(file_path) =~ /^text\//
puts first_line = File.open(attachment.path) { |f| f.readline }
if first_line.include? '-----BEGIN RSA PRIVATE KEY-----'
File.open(cert_file_path, 'w') { |f| f.write(attachment.read) }
else
@credential.errors.add(:cert_file_path, cert_error_msg)
end
else
@credential.errors.add(:cert_file_path, cert_error_msg)
end
end
respond_to do |format|
if @credential.save
format.html { redirect_to credentials_url, notice: 'Credential was successfully mapped.' }
format.js
format.json { render :show, status: :created, location: @credential }
else
format.html { render :new }
format.js
format.json { render json: @credential.errors, status: :unprocessable_entity }
end
end
end
即使设置了错误,记录也会被保存。
#<ActiveModel::Errors:0x0000557781babde8 @base=#<Credential id: nil, alias: "My new credential", user_name: "raj", encrypted_user_pass: "", encrypted_user_pass_iv: "VrT0xsxYtf//cwVx\n", credential_type: "linux", created_at: nil, updated_at: nil, cert_file_path: "/home/rmishra/awsapp/private/certificates/Ruby Enc...", passphrase: "">, @messages={:cert_file_path=>["Certificate is not valid"]}, @details={:cert_file_path=>[{:error=>"Certificate is not valid"}]}>
我知道我可以检查@credential.errors.blank?
然后保存它,你们可以帮我把所有这些逻辑放入模型中吗?
答案 0 :(得分:11)
我认为您希望ActiveRecord
不保存记录,如果您手动设置错误。
但是不是。
ActiveRecord
上的save
命令开始其验证,当其中之一不合适时,AR
设置错误并在save
上返回false。
在您的代码中,没有cert_file_path
字段的验证,因此非常适合保存。
正确的方法是将cert_file_path
的验证从控制器移动到Credential
,在save
事件上,它将调用该验证,如果不合适,则将设置相应的错误,并在false
上返回save
。
答案 1 :(得分:10)
您可以创建一个custom validation method将该逻辑移至模型,并创建虚拟属性以获取对附件对象的访问权限
模型
class Credential < ApplicationRecord
validate :password_or_certificate
enum credential_type: { windows: 1, linux: 2 }
# create a virtual attribute to store attachment
attr_accessor :attachment
# Custom validation method on ActiveRecord object creation
validate :create_certificate, on: :create
def create_certificate
if cert_file_path.present?
cert_error_msg = 'Certificate is not valid'
fm = FileMagic.new(FileMagic::MAGIC_MIME)
file_path = attachment.path
if fm.file(file_path) =~ /^text\//
puts first_line = File.open(attachment.path) {|f| f.readline}
if first_line.include? '-----BEGIN RSA PRIVATE KEY-----'
File.open(cert_file_path, 'w') {|f| f.write(attachment.read)}
else
errors.add(:cert_file_path, cert_error_msg)
end
else
errors.add(:cert_file_path, cert_error_msg)
end
else
errors.add(:cert_file_path, cert_error_msg)
end
end
def password_or_certificate
unless user_pass.blank? ^ cert_file_path.blank?
errors.add(:base, "Please provide a password or a certificate, not both.")
end
end
end
控制器
def create
attachment = params[:credential][:cert_file_path]
cert_file_path = Rails.root.join('private', 'certificates', attachment.original_filename) if attachment.present?
@credential = Credential.new(credential_params)
@credential.cert_file_path = cert_file_path
@credential.attachment = attachment
respond_to do |format|
if @credential.save
format.html {redirect_to credentials_url, notice: 'Credential was successfully mapped.'}
format.js
format.json {render :show, status: :created, location: @credential}
else
format.html {render :new}
format.js
format.json {render json: @credential.errors, status: :unprocessable_entity}
end
end
end
答案 2 :(得分:2)
Rails保存记录时,它将调用内部验证方法,该方法将清除您在运行模型验证代码之前设置的错误消息。因此在验证之外添加错误消息不会阻止保存记录。就您而言,写成
if @credential.errors.empty? && @credential.save
但是我强烈建议您在验证器中编写验证逻辑
答案 3 :(得分:-1)
检查credential_type
的值,可能没有设置为windows
或linux