rake task to expire customers points balance - ruby-on-rails

i am trying to work out how to write a rake tasks that will run daily and find where the days remaining is 0 to update the column amount to zero.
I have the following methods defined in my model, though they don't exactly appear to be working as I am getting the following error in the view
undefined method `-#' for Mon, 27 Jun 2016:Date
def remaining_days
expired? ? 0 : (self.expire_at - Date.today).to_i
end
def expired?
(self.expire_at - Date.today).to_i <= 0
end
def expire_credits
if expired?
self.update(:expire_at => Date.today + 6.months, :amount => 0)
end
end
with the rake tasks i have never written of these and i thought i would be able to call a method of StoreCredit that would expire the points if certain conditions are met but i am not sure how this all works
task :expire_credits => :environment do
puts 'Expiring unused credits...'
StoreCredit.expire_credits
puts "done."
end

# model/store_credit.rb
# get all store_credits that are expired on given date, default to today
scope :expire_on, -> (date = Date.current) { where("expire_at <= ?", date.beginning_of_day) }
class << self
def expire_credits!(date = Date.current)
# find all the expired credits on particular date, and update all together
self.expire_on(date).update_all(amount: 0)
end
end
Since it's a rake task, I think it's more efficient to update all expired ones together
#rake file
result = StoreCredit.expire_credits!
puts "#{result} records updated"
Retrieve Record Count Update
class << self
def expire_credits!(date = Date.current)
# find all the expired credits on particular date, and update all together
records = self.expire_on(date)
records.update_all(amount: 0)
records.length
end
end

You call class method but define instance method. You will need to define class method:
def self.expire_credits

Related

Rails 5 find adult users

I've got pretty old App where I have to create rake task to find all users over 18 and update flags from adult: false to adult: true. I'm wondering what I should use in a rather old version of Rails (I have Rails 5 and Ruby 2.4 on board) to keep the highest performance?
What I have for now is a sidekiq worker with, I think, some syntax error:
class MinorsWorker
include Sidekiq::Worker
def perform
adults = User.where(adults: false).where('date_of_birth >= 18, ?', ((Time.zone.now - date_of_birth.to_time) / 1.year.seconds))
adults.update(adult: true)
end
end
But this code gives me an error:
NameError: undefined local variable or method `date_of_birth' for main:Object
you can do the following. This would update all the matched records in 1 update statement.
If you are concern with db IO, you can batch it.
# in user.rb
class User
scope :adult, -> { where('date_of_birth <= ?', 18.years.ago) }
end
# in your worker file
class MinorsWorker
include Sidekiq::Worker
def perform
update_all
# for update in batches, use #update_all_in_batches
end
private
def update_all
User.adult.where(adult: false).update_all(adult: true)
end
def update_all_in_batches
User.adult.where(adult: false).in_batches(each: 1000) do |users|
users.update_all(adult: true)
sleep 2
end
end
end

Using Simple Scheduler Gem for Scheduling Tasks in a Rails App

I am trying to run a method that adds the response from an API call to Cache, I decided to use the simple_scheduler gem
Below are snippets of code that I am running
# update_cache_job.rb
class UpdateCacheJob < ActiveJob::Base
def perform
return QueuedJobs.new.update_cache
end
end
And
# simple_scheduler.yml
# Global configuration options. The `queue_ahead` and `tz` options can also be set on each task.
queue_ahead: 120 # Number of minutes to queue jobs into the future
queue_name: "default" # The Sidekiq queue name used by SimpleScheduler::FutureJob
tz: "nil" # The application time zone will be used by default if not set
# Runs once every 2 minutes
simple_task:
class: "UpdateCacheJob"
every: "2.minutes"
And the method I have scheduled to run every 2.minutes
class QueuedJobs
include VariableHelper
def initialize; end
def update_cache
#variables = obtain_software_development_table
# First refresh the project Reviews
puts 'Updating reviews...'
#records = Dashboard.new.obtain_projects_reviews.pluck(
obtain_project_reviews_student_variable,
obtain_project_reviews_id_variable,
'Project'
).map { |student, id, project| { 'Student': student, 'ID': id,
'Project': project } }
Rails.cache.write(
:reviews,
#records,
expires_in: 15.minutes
)
#grouped_reviews = Rails.cache.read(
:reviews
).group_by do |review|
review[:Student]&.first
end
puts 'reviews refreshed.'
# Then refresh the coding challenges submissions
puts "Updating challenges submissions.."
#all_required_submissions_columns = Dashboard.new.all_coding_challenges_submissions.all.map do |submission|
{
id: submission.id,
'Student': submission[obtain_coding_chall_subm_student_var],
'Challenge': submission[obtain_coding_chall_subm_challenge_var]
}
end
#all_grouped_submissions = #all_required_submissions_columns.group_by { |challenge| challenge[:Student]&.first }
Rails.cache.write(
:challenges_submissions,
#all_grouped_submissions,
expires_in: 15.minutes
)
puts "challenges submissions refreshed."
end
end
I have been able to reach these methods from the rails console but when ever I run rake simple_scheduler It just logs the first puts and sometimes it does nothing at all.
What do I need to do here?

Setting limit to record entries

I have the following:
after_action :prevent_order_create, :only => [:update, :create]
...
private
def prevent_order_create
#order = Order.find(params[:id]) #line 270
#listing = Order.find_by(params[:listing_id])
#order_seller = #order.where(order_status: [1]).where(:seller)
if #order_seller.count >= 0
#listing.update_column(:listing_status, 3)
end
end
The goal is to limit the amount of orders that can be open for any 1 seller.
When I use this code, I get the following error:
ActiveRecord::RecordNotFound (Couldn't find Order without an ID):
app/controllers/orders_controller.rb:270:in `prevent_order_create'
The order gets created but for whatever reason this issue is happening. Shouldn't the method be getting checked AFTER the order is made without issues?
btw using 0 for testing purposes.
EDIT:
I did:
def prevent_order_create
#order_seller = Order.where(order_status: [1]).where(listing_id: Listing.ids)
if #order_seller.count >= 10
#listing.update_column(:listing_status, 3)
end
end
Seems to work for now. Will update.
Everything you describe is as expected.
An after action is run after the action is already executed, so the record has already been persisted to your DB by the time the exception happens.
The exception is caused because params[:id] is nil, which makes sense for a create action.
Update after clarification in comment
OP said:
I want after create and update... to find any orders with matching :listing_id's and with order_status's of [1] to then count those records. If the count is >= 1000, to then change the listing_status of the Listing
I think the way I would do this is in an after_save in the Order model. Based on your latest edit something like:
scope :status_one, -> { where order_status: 1 } # I'm guessing this should be 1 not [1] as you keep putting
after_save :update_listing
def update_listing
if listing.orders.status_one.count >= 10
listing.update! listing_status: 3
end
end
So that's basically saying that if the associated listing has 10 or more associated orders with order_status=1 then set its status to 3.

Post Scheduling in Ruby Blog

I'm working on post scheduling model by using gem "whenever" with status: published_at, schedule and drafts. But the problem is at given time post is not changing it's status from Schedule to Published_at.
#schedule.rb
every 1.minute do
rake 'scheduler'
end
#example.rake
task scheduler: :environment do
time = Time.zone.now
posts = Post.scheduled.where(published_at: (time))
posts.update_all(status: "Published")
end
task scheduler: :environment do
Post.scheduled.publish_now!
end
in your model post.rb add this line:
def self.publish_now!
where(published_at: Time.now).update_all(status: "Published")
end
I think it's too risk to search by Time.now because it will get exact time in second, but your scheduler is every 1.minutes, so you will have possibility to miss Post because of gaps 60 seconds. So that better you query like this:
def publish_now!
where("status != ? AND published_at <= now()", "Published").update_all(status: "Published")
end

Resend Confirmation instructions to the user using devise

I want to resend confirmation instructions to the user if the user has not confirmed his account after sign up. I am using rails 4. I have this code but its not working.
def resend_confirmation_instructions
users = User.where('confirmed_at IS ?', nil)
users.each do |user|
if (user.created_at < (Date.today - 8))
end_date = (user.created_at.to_date)
start_date = Date.today()
date_diff = (start_date - end_date).to_i
if (date_diff == 3) or (date_diff == 6)
user.send_confirmation_instructions
end
end
end
end
I am using whenever gem to schedule this task every day.
Your code seems alright, but you might have a performance problem when you do users.each with too many users.
Basically users will be an ActiveRecord::Relation, that is an object containing a collection of query parameters. Calling each on it will convert it to an Array as cause the query to be executed. If you have too many objects, that might kill your DB or ruby process.
What about using find_each, to see if it makes a difference?
You are also loading a lot of users that you will probably don't need, as you're executing this check inside the loop:
user.created_at < (Date.today - 8)
That's something else that can affect performance and kill your process. It would be better to add that filter to the active record query.
Try with:
def resend_confirmation_instructions
today = Date.today
users = User.where(confirmed_at: nil)
.where('created_at < ?', (today - 8))
users.find_each(batch_size: 100) do |user|
end_date = user.created_at.to_date
date_diff = (today - end_date).to_i
if date_diff == 3 || date_diff == 6
user.send_confirmation_instructions
end
end
end

Resources