1

I have a Link that is an ActiveRecord object in Rails that has many Comments. Each comment has a score. I'm defining an instance variable @cumulative_score that keeps track of the sum of the score of all of the link's comments. Here is the link definition:

class Link < ActiveRecord::Base
    has_many :comments

    after_initialize :update_cumulative_score

    def cumulative_score
        @cumulative_score
    end

    def update_cumulative_score
        total = 0
        self.comments.each do |comment|
            total = total + comment.score
            puts "comment.score = #{comment.score}" # for debugging
        end
        @cumulative_score = total
        puts "@cumulative_score = #{@cumulative_score}" # for debugging
    end
end

I'm getting some strange results when I input the following into the rails console:

> link = Link.create
> link.cumulative_score 
    # returns 0

> comment = Comment.create(score: 20, link:link)
> link.reload

# puts debugging
comment.score = 20
total = 20
@cumulative_score = 20

> link.cumulative_score
    # returns 0, NOT 20!

Why is the cumulative_score not changing itself to 20, when the puts statement is showing it is 20?

Thanks in advance!

1 Answer 1

1

The after_initialize callback is correctly run after the object is created. In your example you are creating a new object at which point the cumulative score is correctly evaluated to zero. After that you create a new comment and reload your Link object. However, this doesn't create a new Link object, just reloads it's attributes from the database. Because of that, your original evaluation of the cumulative score still stands.

Instead of calculating this on initialization, you should postpone the calculation until you actually need it. If you want to, you can cache the result at this point.

def cumulative_score
  @cumulative_score ||= comments.inject(0) { |sum, comment| sum += comment.score }
end
Sign up to request clarification or add additional context in comments.

2 Comments

Ok, it's just confusing since those puts lines are showing that it is running the code and setting @cumulative_score (seemingly) correctly. Then is some temporary Link object having its @cumulative_score being changed correctly?
Reading your question again, I don't understand why you are getting the second batch of output. The reload call should not trigger the after_initialize callback.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.