Search code examples
ruby-on-rails-3.1

Save method rolls back and returns nil when valid


I am having trouble with Rails' save method; it seems to be failing when it should, but not succeeding when it should.

I have a Claim model, that can be saved with any Status, but if it is to be submitted (status_id == 5) then the terms and conditions have to be accepted.

validates :terms_and_conditions, :acceptance => {:accept => true, :if => :submitted?}

def submitted? # simplified for this example
  status_id == 5
end

However, I am also storing the time that the terms were accepted (under db field tnc_accepted_at), and defining terms_and_conditions as the presence of this field. (This bit works fine, I'm just not sure if it's relevant to my problem.)

def terms_and_conditions
  tnc_accepted_at.present?
end

def terms_and_conditions=(bool) # browser will pass '0' or '1'
  self.tnc_accepted_at = bool.in?([false, nil, 0, '', '0']) ? nil : DateTime.now
end

But here's the rub. The claim starts off in this state:

claim
 => #<Claim id: 51, tnc_accepted_at: nil, status_id: 4>
claim.valid?
 => true

Then I try to submit it:

claim.update_attributes! :status_id => 5
   (0.3ms)  BEGIN
  ClaimItem Load (1.5ms)  SELECT --blah blah blah
  Status Load (0.6ms)  SELECT --blah blah blah
   (0.4ms)  ROLLBACK
ActiveRecord::RecordInvalid: Validation failed: Terms and conditions must be accepted

... which is perfect, but when I try to correct the error:

claim.update_attributes! :terms_and_conditions => true
   (0.3ms)  BEGIN
  ClaimItem Load (1.1ms)  SELECT --blah blah blah
   (0.7ms)  UPDATE "claims" --blah blah blah
   (0.2ms)  ROLLBACK
 => nil

... which is just weird! And I've noticed that I also get this any time I try to save the record, under whatever set of circumstances (using save, save!, update_attributes, update_attributes!, :tnc_accepted_at => DateTime.now, it doesn't matter) - if it's valid, it rolls back and returns nil; if it's invalid, the error is raised as you would expect.


Solution

  • Naturally it's something really simple, after I spent an entire day on it...

    So it seems update_attributes only works properly on records that have already been saved.

    > claim
     => #<Claim id: 51, tnc_accepted_at: nil, status_id: 4>
    > claim.valid?
     => true
    #=========
    > claim.save # This makes all the difference!
       (0.3ms)  BEGIN
      Claim Load (0.4ms)  SELECT --blah blah blah
       (1.0ms)  INSERT INTO "claims" --blah blah blah
       (14.8ms)  COMMIT
     => true
    #=========
    > claim.update_attributes! :status_id => 5
       (0.3ms)  BEGIN
      ClaimItem Load (1.5ms)  SELECT --blah blah blah
      Status Load (0.6ms)  SELECT --blah blah blah
       (0.4ms)  ROLLBACK
    ActiveRecord::RecordInvalid: Validation failed: Terms and conditions must be accepted
    # ... just as expected.
    > claim.update_attributes! :terms_and_conditions => true
       (0.3ms)  BEGIN
      ClaimItem Load (0.8ms)  SELECT --blah blah blah
       (0.8ms)  UPDATE "claims" --blah blah blah
       (11.4ms)  COMMIT
     => true
    # ... hooray!