ActiveRecord(Rails 2.3.8) - 更新现有的,在更新嵌套属性时添加新记录

时间:2010-10-26 14:14:25

标签: ruby-on-rails activerecord

我有一个“用户”模型“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

4 个答案:

答案 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