Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Send parameter to before_save

I am trying to build an app in the "rails way", so this time instead of retrospectively processing records in the database, I am trying to do them using a before_save method, namely this one:

 def make_percentage_from(score)
   percent = (score.fdiv(20) * 100)
   return percent
 end

Every item that comes into the database has a score out of 20, before it gets saved to the database I would like to store this as a percentage, however the issue I am having is that I am unable to send any attribute data via a before_save.

Ideally I'd have

before_save :make_percentage_from(score-to-be-calculated)

How can I do this? Google isn't turning up so much for me and I'm determined not to have to process this data once its stored (providing of course there is another way!)

Thanks and regards

Geoff

like image 801
tob88 Avatar asked Nov 11 '11 15:11

tob88


2 Answers

The short answer: callbacks never have parameters. It is assumed that callbacks take action on the object or record itself. So anything that you would need as a parameter you would need to store either as an attribute (which is saved to the database) or as an instance variable.

like image 196
nathanvda Avatar answered Oct 20 '22 08:10

nathanvda


If score and percentage are attributes of Widget:

class Widget < ActiveRecord::Base
  before_validates :calculate_score_percentage
  validates :percentage, :presence => true
private
  def calculate_score_percentage
    self.percentage = score.fdiv(20) * 100
  end
end

This works because all of your attributes/columns have getter and setter methods automatically defined by ActiveRecord. The reference to score in the calculate_score_percentage method is actually calling the self.score method, which will return the score object/value. We have to use self.percentage explicitly because it would be ambiguous to use percent alone — it could be either defining a local percentage variable, or calling self.percentage=. The default would be the former, which is not what we want in this case.

I'm using before_validates to show that you can use validation still here, which is good for some sanity checking. If you didn't want to do any validation, you could swap it out for before_save without any code changes.

like image 27
coreyward Avatar answered Oct 20 '22 10:10

coreyward