I want to call a function after a particular form is submitted in my mobile app. I am calling it as :
after_save :insert_into_my_table, on: :save_playing_request
save_playing_request is the function which saves the new form. I want to call insert_into_my_table after this. Is it the correct way?
It is not correct way, I think you should use conditional callback or you can also try to customize this as per your requirement.
Like below code.
save_playing_request is just save the data then it should return true/false.
then we can use 'if' with callback.
after_save :insert_into_my_table, if: :save_playing_request?
Now you need to change your method name.
save_playing_request => save_playing_request?
Related
I want to move some class methods for some of my models that are the same to a concern.
One method takes an input and returns something which then should be used to update a record like this:
def create_sort_title
self.sort_title = self.title.gsub(/^the |^a |^an /i, '').gsub(/'|"|!|\?|-/, '').gsub(/(?<!\w) /,'')
end
While it's clear that I need to refactor it to take an input:
def create_sort_title(title)
self.sort_title = title.gsub...
...
I don't understand how I can RETURN a value to update a record - i. e. how to replace the self.sort_title above with something that then is used to update the sort_title of the corresponding record?
The method is called by a before_safe hook:
before_save :create_sort_title
(and I understand once I take an argument, I need to use a lambda like this:
before_save -> { create_sort_title(title) }
You don't really need to pass any arguments if you're using a concern that is included on the model. When you do include ConcernName you're adding class and/or instance methods on the model class/instance itself. So your create_sort_title method that is called from before_save callback will have access to all instance methods, including title and will work as-is just fine
I am trying to update a serialized attribute with some data in an after_save callback on the same object.
I don't want any callbacks to be triggered, for various reasons (side-effects, infinite loop). The typical way to achieve this would be to use update_column, but unfortunately that doesn't work with serialized attributes.
I am aware that I could put conditionals on my callbacks to avoid them getting called again, but it feels that there should be a form of update_attribute which doesn't trigger callbacks, but still works with serialized attributes.
Any suggestions?
This is what I do
serialize :properties, Hash
def update_property(name, value)
self.properties[name] = value
update_column(:properties, properties)
end
Sharing an example below how you can update serialize attribute without callbacks.
Suppose you have a train object, and there is a serialize attribute in that table called: "running_weekdays", that store on which day that particular train runs.
train = Train.last
train.running_weekdays
=> {"Mon"=>"true", "Tues"=>"true", "Wedn"=>"true", "Thur"=>"true", "Frid"=>"true", "Sat"=>"true", "Sun"=>"true"}
Now suppose you want to set the value for all weekdays as false except 'Monday'
changed_weekdays = {"Mon"=>"true", "Tues"=>"false", "Wedn"=>"false", "Thur"=>"false", "Frid"=>"false", "Sat"=>"false", "Sun"=>"false"}
Now you can update this by using update_column as below:
train.update_column(:running_weekdays, train.class.serialized_attributes['running_weekdays'].dump(changed_weekdays))
Hope this will help.
You need to code the hash before updating the column:
update_column(:properties, self.class.serialized_attributes['properties'].dump(properties))
ActiveRecord gives me a back a set of Users. I want to sort those users by a complex function that uses data not persisted in the User object.
Is there a way to use a scope when the data isn't persisted?
Is there a way to write a sort function as a class method, so I can make a call like:
sorted_users = User.first(20).sorted_my_way
i think it is not possible to do it this way.
it is possible to define class methods and scopes that can be called like User.first(20).sorted_my_way but those can only append stuff to the query you create. if you want to sort within ruby, i think that you need to wrap the whole stuff like:
class User
self.sorted_my_way(limit)
first(20).sort_by {...}
end
end
User.sorted_my_way(20)
another thing that you could do would be to use a block style method:
class User
self.sorted_my_way
yield.sort_by {...}
end
end
User.sorted_my_way { first(20) }
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
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.
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.
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.