Why is this an endless loop? ActiveRecord - ruby

class Account < ActiveRecord::Base
after_update :give_user_credit, :on => :update
def give_user_credit
credit = User.current_user.credit + 3.8
User.current_user.update_attribute(:credit, credit)
end
end
When I use this the server hangs and when I come back to the application after a full reboot my credit is in the £1000's.
Whats going on here..
Thanks :D

Looks to me like you are setting the :give_user_credit callback to run every time that the record is updated.
But since the callback updates the record, it then triggers the callback again, which will continue on and on...

You could also use this private method:
model.credit = 10
model.send(:update_without_callbacks)

Related

How to ensure attribute is updated only once in Rails 3 Active Record?

Wondering what could be the best way to handle situations where I need to update particular column and once updated it should not allow user to update again.
I tried using changed? method which checks for record that has been changed and not yet saved. But this would not check a particular attribute in that row.
Any suggestions?
Thanks in advance.
rails g migration add_value_changed_to_YOUR_TABLE_NAME value_changed:boolean
set in the generated file
default: false
and run the migration.
And now, once the value is changed, update this value_changed to true:
before_update :update_value_changed, :check_value_changed
private
def update_value_changed
update(value_changed: true) unless value_changed
end
def check_value_changed
if value_changed
do_something_like_raise_error_or_do_not_save_changes
else
something_else
end
end
Let's assume that you have user class:
class User < ActiveRecord::Base
before_save :check_name_not_changed
private
def check_name_not_changed
if self.name.present? && self.name_changed?
errors.add(:name, "can not be updated")
end
end
end
I am assuming that the name attribute was some how set before.

Run a method after 5 minutes of creation of record in model rails

I'm new to rails,
If I send a request to any user and in case if there is not any response from there with in 5 minutes then request send to another user.
How can I do this in rails please suggest me.
You can make use of run_at option provided by delayed job.
class RecordModel < ActiveRecord::Base
after_create :make_delayed_entry
def make_delayed_entry
Delayed::Job.enqueue(SendMailAndWaitJob.new(parameters), 0, 5.minutes.from_now, :queue => "queue_name")
end
end
SendMailAndWaitJob its the class file(lib file) where you can check request accepted or not.

Code Optimization in Ruby On Rails?

I am developing an iOS event application's backend in ROR. Events has privacy either it is public or private and I have made one method to check for the privacy of the event. Currently I run a query which returns 10k records and it is calling that privacy methods 10k times, which is really a time consuming process. What should I do to optimize the code?
Below is the scenario:
def find_events
events = Event.all # It returns 10k records
events.each do |event|
search_for_privacy(event)
end
end
def search_for_privacy event
# Pure Logic
end
Any help would be appreciated.
Thanks
I assume your events table has a column called public or private which indicates whether or not the event is public. You can then easily find all public events by querying like this:
Events.where(public: true)
You can go further an define a scope:
class Event < ActiveRecord::Base
scope :public, -> { where(public: true) }
end
# now you can do:
Event.public
If you do NOT have a column for indicating the privacy settings, but for example derive the privacy from a description, it may be appropriate to evaluate this when saving a record:
class Event < ActiveRecord::Base
before_save :update_privacy
protected
def update_privacy
self.public = self.is_private?
end
def is_private?
# pure logic
end
end
The upside of this is that you only have to process all the steps necessary to determine the privacy once when saving an event, instead of every time a user is searching for public/private events.
(don't forget to add the column in a migration, and in the migration don't forget to set the privacy on EXISTING records)

How to call after_update callback for a particular column updation?

I have one model called points and in that i have 2 columns named clicked_at and opened_at. Those two columns will not be entered while creating record. Both the columns will be updated manually. Now i want to call a callback only for updating clicked_at column. Is there any way to do this? Help will be appreciated.
You have to check it manually.
def my_callback
if clicked_at_changed?
clicked_at_did_change
end
end
def clicked_at_did_change
# do stuff
end
for this ..observers will be a good option and there are many options when you want to call your code..while updating/creating/deleting/editing/saving ...it goes on.
class PointObserver < ActiveRecord::Observer
##this method will be called everytime AFTER you update point object
def after_update(point)
point.clicked_at =Time.now
point.opened_at =Time.now
point.save!
end
end
enable this observer in application.rb
# Activate observers that should always be running.
config.active_record.observers = :point_observer
You can do whatever you want and also you have many callbacks such as before_save,before_update..etc.
Moreover you can place all your observers in app/observers/..

Delayed job jobs not executing

I'm working with delayed job for the first time and I am not having any luck getting it to work and I don't understand why. The job gets queued, but never executes. It does get removed from the database though, so the worker seems to be processing it, but it doesn't ever run the perform method it seems.
I've set up the following initalizer:
require 'delayed/worker'
Dir.glob("./app/jobs/*.rb").each { |f| require f }
Delayed::Worker.logger = ActiveSupport::BufferedLogger.new("log/dj.log", Rails.logger.level)
module Delayed
class Worker
def self.dj_say(text)
self.logger.info "#{Time.now.strftime('%F %T %z')}: #{text}"
end
end
end
The initializer works, and dj.log does get written to when the work starts/exits.
My job consists of the following:
class UpdateServices
attr_accessor :options
def initialize(options)
self.options = options
end
def perform
#Debugging code
Delayed::Worker.dj_say "starting"
File.open("tmp/test.txt","w").close
#End debugging code
#bunch-o-code-here
Delayed::Worker.dj_say "completed"
end
end
None of this code ever runs. I've tried adding debugging code into the perform method, and it never gets executed, so there is definitely something going on. I call the job from a model like this:
class Service < ActiveRecord::Base
def start_updating!(options)
Delayed::Job.enqueue(UpdateServices.new(options), :priority => 0, :run_at => 30.seconds.from_now, :queue => 'update_services')
end
end
That model is called from my controller like this:
Service.new.start_updating!(params)
My only guess is that I'm called Delayed::Job.enqueue incorrectly, but this seems to be how it should be done based on everything I've read.
It's possible for this to happen if DJ can't deserialize a job for whatever reason since the worker will force the job to permafail. This appears not to be logged by default. Try disabling failed job deletion Delayed::Worker.destroy_failed_jobs = false and seeing if there's an error.

Resources