验证在创建和更新时表现不同的关联对象
Posted
技术标签:
【中文标题】验证在创建和更新时表现不同的关联对象【英文标题】:Validation on associated object behaving differently on create and update 【发布时间】:2016-11-29 07:11:56 【问题描述】:我对检查关联对象数量的自定义验证有疑问。有两个类,Event
和 Guest
。
当用户创建新活动时,他可以选择一些要邀请的客人。保存后,我想检查一下受邀客人的数量。
更新现有事件时验证工作正常。但是在创建新事件时,验证失败,因为self.guests.count
返回0
。
在控制器中,我检查了我选择的客人是否以相同的方式传递给模型:params[:event][:guest_ids]
。
在更新的情况下,我可以看到在调用验证块之前将更新关联表的SQL INSERT INTO
添加到事务队列中。但在新事件的情况下,SQL INSERT
在验证失败之前不会出现。
我在这里缺少什么?我正在考虑一些解决方法,但我确信有适当的方法来实现它。
Rails 版本是 4.2.6
class Event < ActiveRecord::Base
has_and_belongs_to_many :guests
validate :check_guestlist
def check_guestlist
guest_count=self.guests.count
if guest_count < 3
errors.add(“Please invite more guests”)
end
end
class Guest < ActiveRecord::Base
has_and_belongs_to_many :events
end
class EventsController < ApplicationController
def create
@event = current_user.events.new(event_params)
respond_to do |format|
if @event.save
format.html redirect_to @event, notice: 'Event was successfully created.'
else
flash.now[:alert]='Event not saved.'
format.html render action: "new"
end
end
end
def update
@event = current_user.events.find(params[:id])
respond_to do |format|
if @event.update_attributes(event_params)
format.html redirect_to @event, notice: 'Event was successfully updated.'
else
flash.now[:alert]='Changes not saved.'
format.html render action: "edit"
end
end
end
end
【问题讨论】:
在 Event 模型中为客人添加 accept_nested_attributes 并尝试。如果错误仍然存在,请添加您的控制器方法和表单。 谢谢!我尝试添加accepts_nested_attributes_for :guests
但这没有帮助。控制器编码添加到原始问题。
【参考方案1】:
我设法通过替换自定义验证中的一行代码来解决此问题。 如果我更换
guest_count=self.guests.count
与
guest_count=self.guests.to_a.count
我得到了预期的结果。 在更新的情况下,两个表达式返回相同的结果。但是在新记录的上下文中,只有第二个按预期响应。 尽管如此,我仍然不明白为什么第一个版本不起作用。
【讨论】:
【参考方案2】:好吧 self.guests.count 在 create 上不起作用的原因是这实际上是在进行数据库查询,具有事件的范围。
SELECT COUNT(*) FROM
guestsWHERE
guests.
event_id= 1
现在这当然会失败,因为验证发生在客人被保存之前。现在更新它可以工作,因为在数据库中可以找到条目。然而,验证检查的是错误信息 - 数据库中的客人数量不一定与 self.guests 的数量相匹配 - 您可以再添加一位客人,但尚未保存。
您的解决方案确实有效,但我个人认为最好将其写为:
validates :guests, length: minimum: 3, message: 'Please invite more guests'
length
将测试来宾数组的大小 - 例如self.guests.length
实际上与 self.guests.to_a.count
相同
【讨论】:
嗨,大卫,非常感谢您的意见。但我不同意你的说法,即在更新案例中它“正在检查错误的信息”。事实并非如此,这引起了我的头痛。在更新案例中,我看到数据库更新在验证之前被放入事务队列,因此验证成功。我用真实的应用程序对此进行了测试,它在更新案例中运行良好! 试一试...在 Rails 控制台中创建一个有 3 位客人的事件,保存它。检查event.guests.count
...它将如预期的那样为3 ....向事件添加另一个客人...现在调用event.guests.count
..您将看到sql查询运行并且结果仍然是3(即使您加了一个,应该是4)
我做了一个我得到了正确的结果(在你的例子中 = 4),这是有道理的,因为在进行验证之前事务队列中有一个 INSERT INTO 语句。我很困惑...尤其是因为我实施的解决方法有效...以上是关于验证在创建和更新时表现不同的关联对象的主要内容,如果未能解决你的问题,请参考以下文章