views:

110

answers:

4

Hi folks, I am trying to understand the Active Record Callbacks, but they do not work, like I want to.

e.g.

Model

Checklist<ActiveRecord...
attr_accessible :item1, :item2, :done # they are all boolean

before_save :check_done

private
def check_done
  if item1 && item2
   write_attribute :done, true
  else
   write_attribute :done, false
  end
end

this doesn't work if I instantiate an object in the console and try to save it, the save operation returns "false" :(

What's wrong with this code? thanks in advance :)

EDIT: It looks like there is something wrong with the "before_save" call, if I use "after_save", the code works...but the attribute isn't saved (obviously). That's really strange

EDIT 2 Wierd...the development logs shows this

FROM sqlite_master
 WHERE type = 'table' AND NOT name = 'sqlite_sequence'
[0m
  [1m[35mChecklist Load (0.2ms)[0m  SELECT "checklists".* FROM "checklists" ORDER BY checklists.id DESC LIMIT 1
WARNING: Can't mass-assign protected attributes: id

but that is really odd, because if I remove the attr_accessible line I do still get this error...

EDIT 3 If anyone asks, yes I am trying to update an existing record.

EDIT 4 Yes, I like to edit If I type in the console

c.save => # false
c.errors => #<OrderedHash {}>
A: 

PLease try:

def check_done
  if item1 && item2
    done = true
  else
    done = false
  end
end
PeterWong
hmmmm, doesn't work :(but thanks for helping :)
tabaluga
A: 

In your private method, try

def check_done
  self.done = (self.item1 && self.item2) ? true : false
end
Yannis
Buhuuu, that doesn't work either...but thanks for your efforts :)
tabaluga
Did you try by adding the self reference in @PeterWong solution?
Yannis
@Yannis, Yours should be equivalent to mine...There should be other problems. @tabaluga, Does `item1`, `item2` set correctly (true and false as you expected). And is the column `done` is in boolean value? or would you mind adding some debug logs to see if the variables changes as you expected?
PeterWong
@PeterWong: I edited my post above, thanks. ActiveRecord points out "Can't Mass Assign these protected attributes". But if I remove the line attr_accessible the problem persist. And yes, all values are type boolean.
tabaluga
+1  A: 
before_save { |record|
  record.done = item1 && item2
}
buru
thankyou, thankyou, thankyou
tabaluga
+1  A: 

The problem with your callback is that it returns false if either item1 or item2 is false.

From the Active Record Callbacks documentation:

If the returning value of a before_validation callback can be evaluated to false, the process will be aborted and Base#save will return false.

The solution is simple; return true at the end of your callback, like so:

def check_done
  self.done = (item1 && item2)
  return true
end
Pär Wieslander
thankyou, thankyou, thankyou! BTW. to all of you if you are coming to Berlin, drop me a line, you earned a drink :)
tabaluga