Zoinks10
Zoinks10

Reputation: 629

Why isn't my Rails model attribute updated after I run a method?

I have a Rails app with two models - SalesOpportunity and Swot:

SalesOpportunity:

class SalesOpportunity < ActiveRecord::Base
has_many :swots, dependent: :destroy, inverse_of: :sales_opportunity
before_save :update_swot_score


def update_swot_score
    strong = 0
    weak = 0
    opp = 0
    threat = 0

    self.swots.each do |s|
        if s.strength?
            strong = strong + Swot.swot_importances[s.swot_importance]

        elsif s.weakness?
            weak = weak + Swot.swot_importances[s.swot_importance]  

        elsif s.opportunity?
            opp = opp + Swot.swot_importances[s.swot_importance]

        elsif s.threat?
            threat = threat + Swot.swot_importances[s.swot_importance]
        end
    end

        swot_strength_score = strong - weak
        swot_opp_score = opp - threat

        puts swot_strength_score
        puts swot_opp_score

        if swot_strength_score == 0 && swot_opp_score == 0
            swot_score = 0

        elsif swot_strength_score > 0 && swot_opp_score >=0 || swot_strength_score = 0 && swot_opp_score > 0
            swot_score = 1

        elsif swot_strength_score > 0 && swot_opp_score < 0
            swot_score = 2

        elsif swot_strength_score <=0 && swot_opp_score < 0
            swot_score = 3

        elsif swot_strength_score <0 && swot_opp_score >= 0
            swot_score = 4
        end

            puts swot_score 
            return swot_score
                sales_opportunity.update_attributes!
end

end

Swot:

class Swot < ActiveRecord::Base
belongs_to :sales_opportunity, inverse_of: :swots
validates :swot_details, presence: true
validates :sales_opportunity_id, presence: true
enum swot_type: [:strength, :weakness, :opportunity, :threat]
enum swot_importance: { minimal: 1, marginal: 2, noteworthy: 3, significant: 4, critical: 5 }
before_save :update_opportunity_score

def update_opportunity_score
    sales_opportunity.update_swot_score
    sales_opportunity.save
end
end

As you can see I am adding swots to the SalesOpportunities, upon saving a new Swot I run the update_swot_score method in the SalesOpportunity model, which iterates through the swots and calculates a bunch of values before returning a swot_score. I intend to use the swot_score to display a different message per score - however I can't seem to save the swot_score attribute in the database upon completion of the update_swot_score method.

I run this in the console just fine (s is defined as one of my SalesOpportunities with swots already added to it):

irb(main):014:0> s.update_swot_score
2
1
1
=> 1

And this is the correct result - swot_strength_score should be 2, swot_opp_score should be 1, and as a result swot_score should also be 1. However when I then run:

irb(main):015:0> s.swot_score
=> 0

As you can see, swot_score is now nil (that's it's default value in the db). I've tried using .save!, .save, .update_attributes and even trying to save the sales_opportunity at the end of the method, to no avail. I'm sure this is a really dumb question with an obvious answer, but what am I doing wrong here?

Upvotes: 0

Views: 58

Answers (1)

BroiSatse
BroiSatse

Reputation: 44685

This is one of the ruby gotchas. When you do:

swot_score = 0

You create a local variable, you are not changing instance attribute value. Instance attributes like swot_score in your case are methods, and you need to execute a method swot_score= to assign it. By typing:

self.swot_score = 0

It will make parser realize that you want to execute swot_score= method on the current self obeject instead of creating local variable.

Upvotes: 2

Related Questions