处理具有委托类型的委托上的验证错误



我在理解如何使用Rails的委托类型时遇到了一个问题,当涉及到委托上的验证失败时。

具有以下代码

inbox.rb

class Inbox < ApplicationRecord
delegate :name, to: :inboxable
delegated_type :inboxable, types: %w[ Mailbox Messagebox ], dependent: :destroy
end
class Mailbox < ApplicationRecord
include Inboxable
belongs_to :inbox_domain
validates :alias, presence: true, uniqueness: true
def name
"#{self.alias}@#{self.domain.name}"
end
end

messagees_controller.rb

def create
@mailbox =  Inbox.create inboxable: Mailbox.new(mailbox_params)
if @mailbox.save
redirect_to @mailbox.inboxable, notice: "<b>#{@mailbox.name}</b> was created."
else
render :new
end
end
private
def mailbox_params
params.require(:mailbox).permit(:alias, :inbox_domain_id)
end

当我想要创建别名已被采用的邮箱时,会抛出以下错误,因为邮箱。New验证失败

ActiveRecord::NotNullViolation (PG::NotNullViolation: ERROR:  null value in column "inboxable_id" violates not-null constraint
DETAIL:  Failing row contains (13, 2021-09-26 20:48:53.970799, 2021-09-26 20:48:53.970799, Mailbox, null, f).
):

尝试解决方案

处理这种情况的正确方法是什么?我已尝试显式检查邮箱。新的第一个,像这样:

mailbox = Mailbox.new(mailbox_params)
if mailbox.valid?
@inbox =  Inbox.create inboxable: mailbox
......

虽然它在技术上是有效的,但一旦你还必须验证收件箱本身的属性,它就会变得一团糟

使用validates_associated触发关联记录的验证:

class Inbox < ApplicationRecord
delegate :name, to: :inboxable
delegated_type :inboxable, types: %w[ Mailbox Messagebox ], dependent: :destroy
validates_associated :inboxable
end

这将在此模型上的errors对象中添加一个错误("Inboxable is invalidate "),并且如果关联的邮箱无效,则阻止保存。

你想要的控制器是:

def create
# .create both instanciates and saves the record - not what you want here
@mailbox = Inbox.new(inboxable: Mailbox.new(mailbox_params))
if @mailbox.save
redirect_to @mailbox.inboxable, notice: "<b>#{@mailbox.name}</b> was created."
else
render :new
end
end

如果你想显示相关项的错误,你需要访问并遍历其中的errors对象:

# app/views/shared/_errors.html.erb
<ul>
<% object.errors.each do |attribute, message| %>
<li><%= message %>
<% end %>
</ul>
<%= form_with(model: @inbox) do |form| %>
<% if form.object.invalid? %>
<%= render(partial: 'shared/errors', object: form.object) %>
<% if form.object.inboxable.invalid? %> 
<%= render(partial: 'shared/errors', object: form.object.inboxable) %>
<% end %>
<% end %>
# ...
<% end %>

相关内容

  • 没有找到相关文章

最新更新