更新关联时如何销毁其他has_one关系?

时间:2011-08-29 21:22:21

标签: ruby-on-rails transactions controller

我有User has_one Widget

class User
  has_one :widget, :dependent => :destroy
end

class Widget
  belongs_to :user
end

当我为Widget创建新的User时,我想销毁与User相关联的旧版本。

这是我的情况:

创建用户:

user = User.new
user.save
user # => #<User id: 1>

创建用户的小部件:

widget = Widget.new
widget.user = user
widget.save

重新加载并检查小部件:

user.reload
user.widget # => #<Widget id: 1, user_id: 1>

构建一个小部件,注意现有小部件在另一个保存之前被销毁:

user.build_widget # => #<Widget id: nil, user_id: 1>
user.reload
user.widget # => nil

重新创建用户的小部件:

user.create_widget # => #<Widget id: 2, user_id: 1>

创建另一个小部件:

widget = Widget.new :user => user
widget.save

现在,两者都存在:

Widget.find(2) # => #<Widget id: 2, user_id: 1>
Widget.find(3) # => #<Widget id: 3, user_id: 1>

用户是第一个:

user.reload
user.widget # => #<Widget id: 2, user_id: 1>

有没有办法做到这一点:

def create
  @widget = current_user.build_widget(params[:widget])

  respond_to do |format|
    if @widget.save
      format.html { redirect_to widget_path, notice: 'Widget was successfully created.' }
      format.json { render json: @widget, status: :created, location: @widget }
    else
      format.html { render action: 'new' }
      format.json { render json: @widget.errors, status: :unprocessable_entity }
    end
  end
end

在保存之前不删除旧小部件,或者:

def create
  @widget = Widget.new(params[:widget])
  @widget.user = current_user

  respond_to do |format|
    if @widget.save
      format.html { redirect_to widget_path, notice: 'Widget was successfully created.' }
      format.json { render json: @widget, status: :created, location: @widget }
   else
      format.html { render action: 'new' }
      format.json { render json: @widget.errors, status: :unprocessable_entity }
    end
  end

没有保留两份副本?

我不想用像

这样的交易搞砸我的控制器
Widget.transaction do
  old_widget.destroy
  new_widget.save
end

但到目前为止,这似乎是唯一的方法。

2 个答案:

答案 0 :(得分:0)

看起来您有两个使用路径,用户可以在其中创建窗口小部件。从用户端和小部件方面。如果你通过一段代码将它们汇集起来会更好,并进行一些唯一性验证,以确保没有滑倒。

如何在user.create_widget中查找find_or_create_by,以便您可以编辑现有小部件(如果需要更新)或创建新小部件。

答案 1 :(得分:0)

您应该更新 widget 的现有 user 记录,而不是创建新记录并销毁旧记录。 你可以这样做:

class User
  has_one :widget, :dependent => :destroy

  def assign_widget(attr_hash)
    widget ? widget.update(attr_hash) : widget.create(attr_hash)
    widget.reload
  end
end