1

Going mad here. Any pointers gratefully received!

I've got a Delivery model and I'm trying to add a method to update the delivery state, based on delivery lines. This function is defined within the model class, and delivery_state is one of the model attributes:

def updateDeliveryState
  expectedLines = DeliveryLine.where( :delivery_id => id,
                                      :line_state => 'EXPECTED' )
  logger.debug "State1: #{delivery_state}"

  if expectedLines.length == 0
    if delivery_state == 'EXPECTED' || delivery_state == 'RECEIVING'
      delivery_state = 'RECEIVED'               # commenting this line fixes it
      save
    end
  else
    logger.debug "State2: #{delivery_state}"
    if delivery_state == 'EXPECTED'
      logger.debug "Updating to receiving"
      delivery_state = 'RECEIVING'
      save
    end
  end
end

What I'm seeing in the log is that between the 2 logger.debug lines, the delivery_state has been cleared:

State1: EXPECTED
DeliveryLine Load (4.5ms)  SELECT "delivery_lines".* FROM "delivery_lines" 
WHERE "delivery_lines"."line_state" = 'EXPECTED' 
AND "delivery_lines"."delivery_id" = 227
State2:

If I comment out the line marked in the above code, it appears to work OK:

State1: EXPECTED
DeliveryLine Load (9.6ms)  SELECT "delivery_lines".* FROM "delivery_lines" 
WHERE "delivery_lines"."line_state" = 'EXPECTED' 
AND "delivery_lines"."delivery_id" = 227
State2: EXPECTED
Updating to receiving

However, I can see after refreshing that the delivery is still EXPECTED after this??

asc99c
  • 3,815
  • 3
  • 31
  • 54
  • Can you try `self.delivery_state = 'RECEIVED'` inside the first `if` to make sure you are not creating a local variable and are calling the setter instead? – Michael Kohl Oct 21 '11 at 18:59

2 Answers2

3

To elaborate on my comment: it seems like you are creating a local variable in the if. Look:

class Foo
  attr_accessor :bar

  def test
    unless bar
      bar = 1
    end
  end
end

f = Foo.new
f.test
puts f.bar # empty line, bar is nil

Now let's make sure we call the setter:

class Foo
  attr_accessor :bar

  def test
    unless bar
      self.bar = 1
    end
  end
end

f = Foo.new
f.test
puts f.bar # prints 1

See: Why do ruby setters need “self.” qualification within the class?

Community
  • 1
  • 1
Michael Kohl
  • 66,324
  • 14
  • 138
  • 158
  • Thankyou! Got it working and thanks especially for the link explaining what is going on!. I had originally written this code in the controller, and so I knew it should work, but didn't realise what I broke. – asc99c Oct 24 '11 at 10:26
0

can you try to use save(:validate => false) ?

Sometimes Rails has this nasty habit of silently failing validations and not saving.

You probably want to save your state no matter what... :)

Tilo
  • 33,354
  • 5
  • 79
  • 106
  • He does have a bug in his code - it's pretty obvious - so why the downvvote? – Tilo Oct 21 '11 at 19:53
  • I agree, your answer is correct - I guess I never ran into that one, because I always explicitly write self. – Tilo Oct 21 '11 at 20:06