I have a function in my model that changes is as follows:
def compare
self.dirty = 1 if self.dirty == 0
compare_recursive(0, MergeDigestTree.all)
self.dirty = 0;
end
Do I have to call self.save or is it fine like this
Your question is open to two interpretations:
Do you have to call self.save so the record is saved at this point? yes, because an attribute assignation does not commit the change to the database.
Are you forced to call self.save and thus save the record? no. It's ok for a method to change the instance and do not save it. I usually prefer this one, as you give more freedom to the caller.
Whatever the case, document the method accordingly.
You will have to save it yourself, yes. Though I don't see what that method is really doing. :)
No, you should have to call save once changes are made, at some point after this function, if not within this function...
so if you're using this function manually in your app...
resource.compare()
resource.save
Would be fine if you don't want to put the self.save in the compare function.
Related
I have a database trigger that modifies a field on INSERT. Then when I run object.my_attribute it returns nil instead of lets say 42.
If I do object.reload.my_attribute, this is fine. But I don't want to reload the whole object or part of it unless it is necessary. And I believe code shouldn't be concerned when and how an object was created. It should just be correct.
Is it possible to mark that particular attribute as outdated and any attempt to get its value to result in a query that fetches it from database?
For example:
after_save :forget_my_attribute
def forget_my_attribute
forget_field :my_attribute
end
I think it's better to make some service object where field is modified and call it when create the record. CreateModel.call(args) instead of Model.create(args). It will be more clear than database trigger I think
But you can do something like this
after_create_commit :fetch_my_attribute
def fetch_my_attribute
self[:my_attribute] = self.class.find_by(id: id)[:my_attribute]
end
Or more flexible fetch attribute you need dynamically
def fetch_attribute(atr)
self[atr] = self.class.find_by(id: id)[atr]
end
object.fetch_attribute(:my_attribute)
So I am doing this:
#portfolio = current_user.portfolio
#port_stock = PortStock.new(port_stock_params)
stock = Stock.find(port_stock_params[:stock_id])
#port_stock.update!(current_price: stock.price)
respond_to do |format|
if #port_stock.save
The issue I am having is that when I call .update! on #port_stock it actually saves the record before #port_stock.save later.
So my callbacks are being executed twice, which is messing up stuff in my DB.
So how do I update the new instance of #port_stock.current_price without actually saving the #port_stock object before I call it explicitly?
Thanks.
If you're only updating one attribute, you could just use the setter:
#port_stock.current_price = stock.price
Or you could do:
stock = Stock.find(port_stock_params[:stock_id])
#port_stock = PortStock.new(port_stock_params.merge(current_price: stock.price))
Try assign_attributes, it accepts an hash as parameter and don't hit the database, it works just on the object
#port_stock.assign_attributes(current_price: stock.price)
Obviously, if you want just update one field, #Sergio's answer is better and simpler
I have two models, Draft and Pick. Draft creates an array of available Players in an instance variable named 'available_players'. This is done using the 'before_save' callback. The callback runs the instance method 'start' which in turn runs 'set_active_players'. I've tested all of this in my Draft_spec and I have no problems loading players and having them returned in the available_players array. All my draft specs pass.
The problem is that when I try to access the 'available_players' instance variable from Pick.rb, it returns nil. If I call 'draft.start' (the instance method that should run before Draft.rb saves), I can suddenly access the 'available_players' array... it's like the Draft object is not creating the available_players array even though I have the before_save method in place.
Here is the code that fails inside of Pick.rb:
def available_players_returns_nil
#draft_object.available_players
end
Here is the code that works inside of Pick.rb:
def available_players_working
#draft_object.start
#draft_object.available_players
end
I don't want to have to call start every time I call the method because available_players should not need to reload ALL Players. Please help me access available_players!
Links: failing Pick specs, Pick.rb
EDIT:
I should add that #draft_object is found using
#draft_object = Draft.find(self.draft_id)
For a start, this is wrong:
#draft_object = Draft.find(self.draft_id)
You have an association set up, so use it. You can simply use draft within your Pick object to access the Draft it belongs to. No need to assign it to an instance variable called #draft_object.
Same story with player.
Incidentally, your set_available_players method in Draft is just looping through all of the players and adding them to an instance variable. Why are you doing this? Why don't you simply grab the players directly if you need them in Pick? Like this:
#players = Player.all
Also ... I'm somewhat concerned that pretty much all of your tests are commented out. I hope that's not by design?
I want to access a newly created object inside of the conditional statement that created it:
if saved_object = Branch.new(params[:object]).save
puts saved_object.id
end
Activerecord instance save method always return true/false, so you need to initialize the object and check .save on it like below
saved_object = Branch.new(params[:object])
if saved_object.save
puts saved_object.id
end
As Naren Sisodya said, or you can use parentheses to disambiguate what is stored into saved_object (because right now saved_object holds the result of the .save call).
if (saved_object = Branch.new(params[:object])).save
puts saved_object.id
end
In this form, the saved_object variable will hold the database record and then .save will be called on that record. This is likely what you intended, but not what you got due to operator precedence rules in ruby.
When creating a record i know you can use the method
.first_or_create!
to create records that don't already exist in the model. I need to do the same for when updating a model. I have an app that runs a rake task to apply a score to a column in my model.
prediction.update_attributes!(score: score)
I only want to update the scores that have not been updated yet.
is this possible?
Thanks
I think you might be looking for the try method which will attempt to call a method on an object that is potentially nil.
Example:
>> prediction.try(:update_attributes!, :score => some_new_score)
If prediction is nil it will just return nil, not throw a NoMethodError. If prediction is an object representing an existing record, then it will call the method on the object and update its score attribute.
http://api.rubyonrails.org/classes/Object.html#method-i-try
I agree with juanpastas that Rails will only save to the db if something has actually changed. IF you want to be more explicit in your code, Why not use the '.changed?' flag to save only dirty records? Look here for more details.