首先,我使用的是 Rails 3.2.1 和 ruby 1.9.3p392
我有两种型号,ad_user和设备
一个ad_user
有很多devices
,一个device
属于一个ad_user
。
我的模型如下:
class AdUser < ActiveRecord::Base
has_many :devices
class Device < ActiveRecord::Base
belongs_to :device_type
belongs_to :device_status
belongs_to :ad_user
validates_presence_of :name
validates_uniqueness_of :name
validates_presence_of :serial
validates_uniqueness_of :serial
validates_presence_of :device_type_id
validates_presence_of :device_status_id
validates_presence_of :ad_user_id
before_update :before_update_call
before_save :before_save_call
before_create :before_create_call
before_validation :before_validation_call
protected
def before_update_call
p self.name
p self.ad_user_id
p "-=-=-=-=-=-=-=-=-"
p "before_update_call"
self.ad_user_id = 1 if self.ad_user_id.nil? || self.ad_user_id.blank?
end
def before_save_call
p self.name
p self.ad_user_id
p "-=-=-=-=-=-=-=-=-"
p "before_save_call"
self.ad_user_id = 1 if self.ad_user_id.nil? || self.ad_user_id.blank?
end
def before_create_call
p self.name
p self.ad_user_id
p "-=-=-=-=-=-=-=-=-"
p "before_create_call"
self.ad_user_id = 1 if self.ad_user_id.nil? || self.ad_user_id.blank?
end
def before_validation_call
p self.name
p self.ad_user_id
p "-=-=-=-=-=-=-=-=-"
p "before_validation_call"
self.ad_user_id = 1 if self.ad_user_id.nil? || self.ad_user_id.blank?
end
当我使用
u = AdUser.first
u.device_ids=[1,2]
我可以看到before_validation_call
、before_save_call
和before_update_call
打印到控制台,但是当我从用户取消分配这些设备时:
u.device_ids=[]
它导致一个简单的:
SQL (2.0ms) UPDATE "devices" SET "ad_user_id" = NULL WHERE "devices"."ad_user_id" = 405 AND "devices"."id" IN (332, 333)
没有调用任何回调,尽管模型应该验证存在,但我的设备最终ad_user_id
为零。我计划在保存或更新之前使用回调来检查ad_user_id
是否为零,但它们甚至没有被调用。
我在这里做错了什么吗?
不幸的是,我认为这是预期的行为。更新关联时不应依赖触发的回调,因此将隐式更新基础模型。
不过,您可以做的是尝试访问devices
字段。 device_ids
在较低水平上表现不同。
如果合适,还可以考虑使用关联回调。
附言只是一个小说明:在 Rails 中您可以使用 self.ad_user.present?
而不是 self.ad_user_id.nil? || self.ad_user_id.blank?
.此外,还可以合并validates_presence_of
语句。
好吧,在我的ad_user
控制器的update
方法中,在update_attributes
之前,我添加了:
old_device_ids = @ad_user.device_ids
在update_attributes
之后,我补充说:
(old_device_ids - AdUser.find(params[:id]).device_ids).each do |device|
Device.find(device).update_attributes(:ad_user_id => 1)
end
我之前已经这样做了,但我想找到一种合适的"Rails 方式"。