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

Ben*_*nns 5 controller transactions ruby-on-rails

我有一个Userhas_one Widget.

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

class Widget
  belongs_to :user
end
Run Code Online (Sandbox Code Playgroud)

当我Widget为a 创建一个新的时候User,我想要销毁与之相关的旧的User.

这是我的情况:

创建用户:

user = User.new
user.save
user # => #<User id: 1>
Run Code Online (Sandbox Code Playgroud)

创建用户的小部件:

widget = Widget.new
widget.user = user
widget.save
Run Code Online (Sandbox Code Playgroud)

重新加载并检查小部件:

user.reload
user.widget # => #<Widget id: 1, user_id: 1>
Run Code Online (Sandbox Code Playgroud)

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

user.build_widget # => #<Widget id: nil, user_id: 1>
user.reload
user.widget # => nil
Run Code Online (Sandbox Code Playgroud)

重新创建用户的小部件:

user.create_widget # => #<Widget id: 2, user_id: 1>
Run Code Online (Sandbox Code Playgroud)

创建其他小部件:

widget = Widget.new :user => user
widget.save
Run Code Online (Sandbox Code Playgroud)

现在,两者都存在:

Widget.find(2) # => #<Widget id: 2, user_id: 1>
Widget.find(3) # => #<Widget id: 3, user_id: 1>
Run Code Online (Sandbox Code Playgroud)

用户是第一个:

user.reload
user.widget # => #<Widget id: 2, user_id: 1>
Run Code Online (Sandbox Code Playgroud)

有没有办法做到这一点:

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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

结束

没有保留两份副本?

我不想用我这样的交易搞砸我的控制器

Widget.transaction do
  old_widget.destroy
  new_widget.save
end
Run Code Online (Sandbox Code Playgroud)

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

cgr*_*cgr 1

看起来您有两个使用路径,用户可以在其中创建小部件。从用户端和小部件端。如果您通过一段代码将它们集中起来,并进行一些唯一性验证以确保不会出现任何失误,那就更好了。

在 user.create_widget 中使用 find_or_create_by 怎么样,以便您可以在需要更新现有小部件或创建新小部件时对其进行编辑。