How to update an attribute after create or update - ruby-on-rails-5.2

I’m new to rails and I’m trying to figure out the following.
I’ve got a class Order which has attributes name, status and radius. The possible status are [draft, posted, taken]. The radius can change from 500 to 5k incrementing 500 each time a loop runs. I would like to know how can I make the radius to change depending on the status and the time that has pass.
If #order.status = draft, then status = 500.
If #order.status = posted, then the radius’ value will start with 500 but increment by 500 every 10 seconds until it gets to 40.
If #order.status = taken, then the radius’ value will be equal to whatever the radius is when the status changed to taken.
if order.status != taken after the 40 seconds, the #order.status = draft and #order.radius = 500
The following code runs well in ruby for visualization only, if you copied an run it on the teminal you will see it running well.
count = 1
initial_radius = 500
puts "Enter the status: "
status = gets
status = status.chomp
while status == 'posted' && count < 4 # this will be the one deciding (n) #times for 10k max radius of search otherwise get back to draft
puts ""
puts "Run #{count}"
radius = 500
puts "Radius = #{radius}"
n = 1
while status == 'posted' && n <10
status = 'posted'
puts " Status is now = #{status.capitalize}! "
sleep(1)
puts "n = #{n}"
puts "Enter the status: "
status = gets
status = status.chomp
n += 1
start = Time.now
puts "Radius = #{radius}"
end
if status == 'posted'
count += 1
radius *= count
puts "New Radius = #{radius}"
elsif status == 'taken'
radius *= count
puts ""
puts "Order has been Taken with radius #{radius}!!"
puts ""
end
#radius = 500 This was removed as it didn't affect
end
if status == 'taken'
puts ""
else
puts ""
puts "No company took the order"
puts "Order has gone back to status Draft and its radius is #{initial_radius} "
puts ""
end
But when I try the following to see how the server behaves and I create a new Order it hangs until it finishes processing any order that has been placed before. I know that it hangs because of the sleep method. The code below is done only to see how it will behave. It does update the radius after 15 seconds but no one would like to use an application that needs to wait until someone else finish their bit.
Order model
after_save :change_radius, on: [:create, :update]
def change_radius
if self.status == 'posted'
sleep 15
update_column(:radius, 1000)
elsif self.status == 'draft'
update_column(:radius, 500)
end
end
My question is. How can I make it to work so it will be possible for any other user to use the application (create an order) without any hanging until it finish dealing with another user’s order. I think it may need use of Active jobs or something similar but unsure how to set it up if this is the case. I would appreciate any guidance on this matter.

For a process that takes a long time to complete, consider putting it in a background process. I would check out using sidekiq with redis. It's a good option for background processing.

Related

Reset a counter in Ruby

I have the following code to compile jobs from github jobs API. How do I reset a counter back to 0 every time I call on a new city? I've tried putting it in several different places with no luck.
def ft_count_and_percentage
##url += #city
uri = URI(##url)
response = Net::HTTP.get(uri)
result = JSON.parse(response)
result.each do |job|
if job["type"] == "Full Time"
##fulltime_count += 1
end
end
puts "Total number of jobs in #{#city}: #{result.length}"
if ##fulltime_count > 0
puts ("full time percent ") + "#{(##fulltime_count/result.length) * 100}"
else
puts "No FT Positions"
end
end
##fulltime_count is defined outside this method to start at 0. Currently, as expected the counter just keeps adding jobs every time I add a new city.
boston = Job.new("Boston")
boston.ft_count_and_percentage
sf = Job.new("San Francisco")
sf.ft_count_and_percentage
la = Job.new("Los Angeles")
la.ft_count_and_percentage
denver = Job.new("Denver")
denver.ft_count_and_percentage
boulder = Job.new("Boulder")
boulder.ft_count_and_percentage
chicago = Job.new("Chicago")
chicago.ft_count_and_percentage
ny = Job.new("New York City")
ny.ft_count_and_percentage
You may need to reset it inside Job init
class Job
def initialize
##count = 0
end
def ft_count_and_percentage
#the blah you already have
end
end

error when creating hash in simple Credit Card class for ruby

I am creating a simple CC class that can create and update a credit card. To do this, I have created cc_bal{} as an instance object so it can update respect credit cards. The hash is to save and update a person and the amount on their cc. I end up getting an output of just the original amount that was created and not the updated amount
Heres the code:
class CC
def initialize(cc_name, cc_bal = {}, open_cc = false)
#cc_name = cc_name
#cc_bal = cc_bal
#open_cc = open_cc
end
def create(initAmount, person)
if initAmount > 0
#open_cc = true
#cc_bal[:person]=initAmount
puts "congrats #{person} on opening your new #{#cc_name} CC! with $#{#cc_bal[:person]}"
else
puts "sorry not enough funds"
end
end
def update(amount, person)
if #open_cc == true
#cc_bal[:person] + amount
else
puts "sorry no account created, #{person}"
end
puts "#{person} has CC balance of #{#cc_bal[:person]}"
end
end
#chase = Bank.new("JP Morgan Chase")
#wells_fargo = Bank.new("Wells Fargo")
me = Person.new("Shehzan", 500)
friend1 = Person.new("John", 1000)
#chase.open_account(me)
#chase.open_account(friend1)
#wells_fargo.open_account(me)
#wells_fargo.open_account(friend1)
#chase.deposit(me, 200)
#chase.deposit(friend1, 300)
#chase.withdraw(me, 50)
#chase.transfer(me, wells_fargo, 100)
#chase.deposit(me, 5000)
#chase.withdraw(me, 5000)
#puts chase.total_cash_in_bank
#puts wells_fargo.total_cash_in_bank
credit_card = CC.new("Visa")
credit_card.create(10,me)
credit_card.update(50,me)
credit_card.create(20,friend1)
credit_card.update(40,friend1)
Please disregard the function calls that are commented out.
Any idea why the CC's are not updatiing?
if #open_cc == true
#cc_bal[:person] + amount
else
You increase the amount, but you don't set the new value anywhere. It should be
if #open_cc == true
#cc_bal[:person] += amount
else
Note. The code needs some serious refactoring and cleanup.

rTurk fails getting results from Amazon Mechanical Turk

I am experiencing a very strange problem. I am able to submit a HIT to Amazon Mechanical Turk correctly. I have a cron that keeps checking if there is any job ready to be reviewed. However, when a job is completed I am not receiving it but the HIT is disposed (what is done inside the function to review it). The strange thing is that this problem is not happening always, but quite often.
This is the code of the function to review the HITs:
def self.review_hits
hits = RTurk::Hit.all_reviewable
p "HITS"
p hits
puts "REVIEWABLE HITS: " + hits.count.to_s
hits_results = {}
unless hits.empty?
hits.each do |hit|
puts "IN EACH HIT"
p hit
results = []
hit.expire!
# Get results for each HIT assignment
hit.assignments.each do |assignment|
# Check if the assignmment has been submitted. It can be the case where the maximum waiting time
# for the job to finish expired and there remain assignments that are not submitted
if assignment.status == 'Submitted'
p "STATUS 1"
p assignment.status
temp = {}
temp[:worker_id] = assignment.worker_id
temp[:answer] = assignment.answers
p "STATUS 2"
p assignment.status
assignment.approve!
results << temp
end
end
begin
hit.dispose!
rescue
end
hits_results[hit.id] = {}
hits_results[hit.id][:results] = results
end
# Let Rails know that there are new results
AmazonTurkHit.store_results(hits_results)
end
end
So the puts "REVIEWABLE HITS:" is 0 but the HIT is disposed. Does anyone know why?
After some time becoming crazy about this I realised that the problem was very silly... I had two instances of the system running, one in production and one in staging but both with the same AWS account so sometimes the HIT was caught by the other system... :)

Twitter rate limit hit while requesting friends with ruby gem

I am having trouble printing out a list of people I am following on twitter. This code worked at 250, but fails now that I am following 320 people.
Failure Description: The code request exceeds twitter's rate limit. The code sleeps for the time required for the limit to reset, and then tries again.
I think the way it's written, it just keeps retrying the same entire rejectable request, rather than picking up where it left off.
MAX_ATTEMPTS = 3
num_attempts = 0
begin
num_attempts += 1
#client.friends.each do |user|
puts "#{user.screen_name}"
end
rescue Twitter::Error::TooManyRequests => error
if num_attempts <= MAX_ATTEMPTS
sleep error.rate_limit.reset_in
retry
else
raise
end
end
Thanks!
The following code will return an array of usernames. The vast majority of the code was written by the author of: http://workstuff.tumblr.com/post/4556238101/a-short-ruby-script-to-pull-your-twitter-followers-who
First create the following definition.
def get_cursor_results(action, items, *args)
result = []
next_cursor = -1
until next_cursor == 0
begin
t = #client.send(action, args[0], args[1], {:cursor => next_cursor})
result = result + t.send(items)
next_cursor = t.next_cursor
rescue Twitter::Error::TooManyRequests => error
puts "Rate limit error, sleeping for #{error.rate_limit.reset_in} seconds...".color(:yellow)
sleep error.rate_limit.reset_in
retry
end
end
return result
end
Second gather your twitter friends using the following two lines
friends = get_cursor_results('friends', 'users', 'twitterusernamehere')
screen_names = friends.collect{|x| x.screen_name}
try using a cursor: http://rdoc.info/gems/twitter/Twitter/API/FriendsAndFollowers#friends-instance_method (for example, https://gist.github.com/kent/451413)

Best way to check for a new tweet

Heres a piece of code from my irc bot. What it does is that it checks for new tweets at an specific account, then replies it in the channel.
Now, is there an better way to check for new tweets? that for i in 1..999999999 feels a bit unoptimal, and ddos'y.
tweetzsr = {}
xzsr = {}
zsr = {}
on :message, ".start zsr" do |m|
if zsr[m.channel] == true
m.reply "already doing it.."
else
m.reply "ok."
zsr[m.channel] = true
for i in 1..99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
sleep 60
puts "#{xzsr[m.channel]} = x, tweetzsr = #{tweetzsr[m.channel]}"
tweetzsr[m.channel] = Twitter.user_timeline("twiitterracount").first.text
if xzsr[m.channel] == tweetzsr[m.channel]
nil
else
m.reply "#{tweetzsr[m.channel]} - via twitter feed"
xzsr[m.channel] = tweetzsr[m.channel]
end
end
end
end
First of all, for an infinite loop use the loop method.
Best for this kind of thing is to use Twitter's streaming api. This api will send a single request to Twitter, which will then push any new data to your client. For that there is a gem called TweetStream.
Example usage:
TweetStream::Client.new.userstream do |status|
m.reply "#{status.text} - via twitter"
end
Is that your infinite loop?
Change it to this to improve sanity
loop do
sleep 60
newtweet[m.channel] = Twitter.user_timeline("twitteracount").first.text
next if oldtweet[m.channel] == newtweet[m.channel]
m.reply "#{newtweet[m.channel]} - via twitter"
oldtweet[m.channel] = newtweet[m.channel]
end
You're missing the two end keywords.

Resources