我有一个“用户”模型“has_one”“成员资格”(一次有效)。出于审计和数据完整性的原因,我希望如此,如果用户的成员身份发生变化,旧/当前记录(如果存在)交换了非活动/活动标志,并为新更改的记录添加新行。如果成员资格没有变化,我想忽略更新。我已尝试在我的用户模型上使用“before_save”回调实现此功能,但多次失败。非常感谢任何帮助。
模型:
class User < ActiveRecord::Base
has_one :membership, :dependent => :destroy
accepts_nested_attributes_for :membership, :allow_destroy => true
end
class Membership < ActiveRecord::Base
default_scope :conditions => {:active => 1}
belongs_to :user
end
答案 0 :(得分:1)
我认为这是一个非常优雅的解决方案。这是您的用户模型:
class User < ActiveRecord::Base
has_one :membership, :dependent => :destroy
accepts_nested_attributes_for :membership
def update_membership_with_history attributes
self.membership.attributes = attributes
return true unless self.membership.changed?
self.membership.update_attribute(:active, false)
self.build_membership attributes
self.membership.save
end
end
此update_membership_with_history方法允许我们处理已更改或未更改的记录。接下来是会员模型:
class Membership < ActiveRecord::Base
default_scope :conditions => {:active => true}
belongs_to :user
end
我稍微改变了一下,因为active应该是一个布尔值,而不是1和0。更新您的迁移以匹配。现在是更新操作,这是您的脚手架中唯一需要更改的部分:
def update
@user = User.find(params[:id], :include => :membership)
membership_attributes = params[:user].delete(:membership_attributes)
if @user.update_attributes(params[:user]) && @user.update_membership_with_history(membership_attributes)
redirect_to users_path
else
render :action => :edit
end
end
我们只是解析出会员资格属性(因此您仍然可以在视图中使用fields_for)并单独更新它们,并且仅在需要时进行更新。
答案 1 :(得分:0)
你看过acts_as_versioned了吗?在before_save
的{{1}}中,您可以创建Membership
的新版本,即User
。
答案 2 :(得分:0)
为什么不假设最新的会员资格是活跃会员资格。这样可以省去很多麻烦。
class User < ActiveRecord::Base
has_many :memberships, :dependent => :destroy
end
class Membership < ActiveRecord::Base
nested_scope :active, :order => "created_at DESC", :limit => 1
belongs_to :user
def update(attributes)
self.class.create attributes if changed?
end
end
然后你可以使用
@user.memberships.active
获取活跃会员资格,您只需更新任何会员资格即可获得新会员资格,这将成为活跃会员资格,因为它是最新会员资格。
答案 3 :(得分:0)
搞定了。虽然它可能不是最好的实现,但我所有的测试都在通过。感谢输入人员。
before_save :soft_delete_changed_membership def soft_delete_changed_membership if !membership.nil? then if !membership.new_record? && membership.trial_expire_at_changed? then Membership.update_all( "active = 0", [ "id = ?", self.membership.id ] ) trial_expire_at = self.membership.trial_expire_at self.membership = nil Membership.create!( :user_id => self.id, :trial_expire_at => trial_expire_at, :active => true ) self.reload end end end