0

I want to set a default value if the variable is not set.

Here are valid values (which should not get overwritten): true false 0 1 "some string"

Here is how I'm currently trying to do this. Is this the right way?

  before_save :set_defaults

  def set_defaults
    self.is_approved = false if self.is_approved.nil?
  end

If this is indeed correct, is there a better syntax? In PHP we had isset() for this sort of stuff.

Hopstream
  • 6,391
  • 11
  • 50
  • 81
  • Looks like what you want is `defined?`. http://stackoverflow.com/questions/288715/checking-if-a-variable-is-defined-in-ruby – Ryan Ballantyne Oct 31 '11 at 10:42
  • you can try: if (!defined?(self.is_approved)) then – Alan Oct 31 '11 at 10:43
  • it looks well, though personally I prefer defaults to be set on initialization, it's more explicit and they pass validations: https://github.com/FooBarWidget/default_value_for – tokland Oct 31 '11 at 11:02

2 Answers2

4

The idiomatic ruby version for this would be to write:

is_approved ||= false

which would set is_approved to false if is_approved is falsey: that means nil or false. Since setting to false if false is idempotent, it is not wrong.

Otherwise you could write:

is_approved = false unless is_approved.present?

which is identical to what you wrote:

is_approved = false if is_approved.nil?

but I find it slightly more readable. So yes: that is also the right way to do it.

You will notice that in ruby there are many ways to achieve the same thing. This is the part of programmer happiness: you choose which way suits you the best, and is most expressive at that place (because sometimes one is better suited, and sometimes the other). But for beginners it is sometimes confusing :)

nathanvda
  • 49,707
  • 13
  • 117
  • 139
  • `self.is_approved = !!is_approved` will effectively do a Boolean cast, which will turn `nil` to `false`, leave `false` unchanged, leave `true` unchanged and turn any other truthy value to `true`. – d11wtq Oct 31 '11 at 12:54
  • @d11wtq: nice addition, but the OP also stated the `is_approved` can contain a string, which of course needs to remain. Secondly your statement will always do an assignment, which may or may not be the wanted effect (e.g. if counting the number of assignments or changing `updated_at`). – nathanvda Oct 31 '11 at 13:41
0

If you want to set a variable value of an object when it's unset (nil) and leave the actual value otherwise, you could do something shorter, like:

before_save :set_defaults

def set_defaults
  self.is_approved ||= false
end
santuxus
  • 3,662
  • 1
  • 29
  • 35
  • That seems to break if my value is already false and I want to set some other default. For example if `abc=false` then `abc ||= true` will set it to true (even though we would want to keep the false value here). – Hopstream Oct 31 '11 at 10:51
  • a caveat: this won't work if you want to set true as default value, since x ||= true will turn a x=false into x=true – tokland Oct 31 '11 at 10:51
  • Is there any other simpler short hand available in ruby that would work in all cases? – Hopstream Oct 31 '11 at 10:53
  • it comes from OR operator: false || 5 => 5, nil || 5 => 5, in general !nil == !false – santuxus Oct 31 '11 at 11:00
  • I guess in case of 'true' as a default value, you will have to test if it's nil. As it was suggested in the comment, you could use defined, but in this case self.is_approved.nil? == !defined(self.is_approved) and for me the first option is more natural, so for 'true' value I would leave the code as you presented it. – santuxus Oct 31 '11 at 11:06
  • Don't do that in a before_save callback - a method in Ruby returns the last eval, and in your case this is sometimes `false`, and that will halt the execution of the callback chain. – eugen Oct 31 '11 at 11:34