开发者

How do I destroy the other has_one relation when updating an association?

开发者 https://www.devze.com 2023-03-31 09:10 出处:网络
I have a User which has_one Widget. class User has_one :widget, :dependent => :destroy end class Widget

I have a User which has_one Widget.

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

class Widget
  belongs_to :user
end

And when I create a new Widget for a User, I want to destroy the old one associated with the User.

Here's my situation:

Create a user:

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

Create user's widget:

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

Reload and check the widget:

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

Build a widget, notice that the existing widget is destroyed before the other is saved:

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

Recreate user's widget:

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

Create another widget:

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

Now, both exist:

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

And user's is the first:

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

Is there any way to do this:

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

without deleting the old widget before saving, or this:

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

end

without keeping two copies around?

I don't want to muck up my controllers with transactions like

Widget.transaction do
  old_widget.destroy
  new_widget.save
end

but so far, this seems like the only way.


It looks like you have two usage paths where a user can create widgets. From the user side and from the widget side. It would be better if you funneled them through one piece of code, and put some uniqueness validations up to insure there are no slip ups.

how about a find_or_create_by in user.create_widget so that you can edit the existing widget if it needs to be updated or you create a new one.


You should update the existing widget record for the user instead of creating a new one and destroying the old one. You can do something like this:

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
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号