Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 414
Benjamin Manns Avatar asked Nov 14 '22 18:11

Benjamin Manns


1 Answers

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.

like image 176
cgr Avatar answered Dec 05 '22 22:12

cgr