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.
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
精彩评论