Catfish
Catfish

Reputation: 19314

Rails active record not saving as expected

I have an update method that is not saving database records as expected.

Basically what's happening is that the arrangement_id is not saving to the timeslot table as I would expect with the method below.

From the output of my variable's after the save!'s I would think that the arrangement_id would save in the timeslot table.

Can anyone tell me why it's not and what i'm doing wrong here?

# PUT /arrangements/1
  def update
    success = false

    @arrangement = Arrangement.find(params[:id])

    # Remove arrangement id from old timeslot
        old_timeslot = Timeslot.find(@arrangement.timeslot_id)
        old_timeslot.arrangement_id = nil

        # Save arrangement id to new timeslot
        new_timeslot = Timeslot.find(@arrangement.timeslot_id)
        new_timeslot.arrangement_id = @arrangement.id

        p "old_timeslot = #{old_timeslot.inspect}"
        p "new_timeslot = #{new_timeslot.inspect}"

        old_timeslot.save!
        new_timeslot.save!

        p "after save old_timeslot = #{old_timeslot.inspect}"
        p "after save new_timeslot = #{new_timeslot.inspect}"

        @arrangement.update_attributes!(params[:arrangement])
        success = true

    respond_to do |format|
      if success
        format.html { redirect_to @arrangement, notice: 'Arrangement was successfully updated.' }
      else
        format.html { render action: "edit" }
      end
    end
  end

Here's the console output:

# These are before the old_timeslot and new_timeslot variables are saved
"old_timeslot = #<Timeslot id: 17306, location_id: 3, arrangement_id: nil, timeslot: \"2014-01-10 17:00:00\", created_at: \"2013-05-20 04:03:30\", updated_at: \"2014-01-11 01:35:55\">"
"new_timeslot = #<Timeslot id: 17306, location_id: 3, arrangement_id: 839, timeslot: \"2014-01-10 17:00:00\", created_at: \"2013-05-20 04:03:30\", updated_at: \"2014-01-11 01:35:55\">"

# These are after the old_timeslot and new_timeslot variables are saved
"after save old_timeslot = #<Timeslot id: 17306, location_id: 3, arrangement_id: nil, timeslot: \"2014-01-10 17:00:00\", created_at: \"2013-05-20 04:03:30\", updated_at: \"2014-01-11 01:37:09\">"
"after save new_timeslot = #<Timeslot id: 17306, location_id: 3, arrangement_id: 839, timeslot: \"2014-01-10 17:00:00\", created_at: \"2013-05-20 04:03:30\", updated_at: \"2014-01-11 01:35:55\">"


Started PUT "/arrangements/839" for 127.0.0.1 at 2014-01-10 19:37:09 -0600
Processing by ArrangementsController#update as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"REBgw/kRwlclqS670aIcIZ1Ug6kgxr/itEevwMQO2w8=", "arrangement"=>{"family_name"=>"smith", "location_id"=>"3", "date"=>"01/10/2014", "timeslot_id"=>"17306", "need"=>"myNeed", "notes"=>"mynotes", "user_id"=>"66"}, "button"=>"", "id"=>"839"}
  User Load (0.4ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1
  Setting Load (0.4ms)  SELECT `settings`.* FROM `settings` 
  Arrangement Load (0.4ms)  SELECT `arrangements`.* FROM `arrangements` WHERE `arrangements`.`id` = 839 LIMIT 1
  Timeslot Load (0.2ms)  SELECT `timeslots`.* FROM `timeslots` WHERE `timeslots`.`id` = 17306 LIMIT 1
  CACHE (0.0ms)  SELECT `timeslots`.* FROM `timeslots` WHERE `timeslots`.`id` = 17306 LIMIT 1
   (0.1ms)  BEGIN
   (0.3ms)  UPDATE `timeslots` SET `arrangement_id` = NULL, `updated_at` = '2014-01-11 01:37:09' WHERE `timeslots`.`id` = 17306
   (53.5ms)  COMMIT
   (0.1ms)  BEGIN
   (0.2ms)  COMMIT
Redirected to http://localhost:3000/arrangements/839
Completed 302 Found in 168ms (ActiveRecord: 55.5ms)

Upvotes: 1

Views: 710

Answers (1)

David Ongaro
David Ongaro

Reputation: 3946

First of all it's strange that you try to do two saves of the same record in succession. As long as the id of these records are the same the second save should just overwrite the first one.

On the other hand since Rails 2.0 or so Rails has the notion of "dirty" objects and attributes. So it might well be that the assignment

new_timeslot.arrangement_id = @arrangement.id

doesn't actually change anything, if the arrangement_id attribute already had the value of @arrangement.id. Therefore the new_timeslot object wouldn't get marked as 'dirty' and rails can skip the save! as an optimization measure. Even though you updated the very same record in the DB beforehand, new_timeslot still doesn't get marked as 'dirty', because you did that in a different instance.

So either you want to save two different records, then you should change the id of at least one to nil (or create a new record and initialize it with the same attributes) or you only want to update the record with the new_timeslot attributes, then there is no reason to call save! on old_timeslot.

Upvotes: 1

Related Questions