RoR + Sidekiq background processes - ruby-on-rails

I'm trying to get my list to go closed when the End Date is met.
Could anyone help me? I'm using sidekiq for background processes and I already have my list passing closed status, but not when it reaches the end date.
My table
create_table "lists", force: :cascade do |t|
t.integer "user_id"
t.binary "uuid", limit: 36
t.string "name"
t.string "description"
t.datetime "end_date"
t.integer "status", default: 1
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id"], name: "index_lists_on__user_id"
I did this in the sidekiq so that my list goes to the disabled state
class HardJob
include Sidekiq::Job
def perform(list_id)
list = List.find list_id
list.disabled!
return 0
end
end

You can schedule a job with a cronjob that runs every day at a specific time.

Related

Rails – I want to change the status of my table by putting a certain time?

I've only been in RoR for a short time.
I have a list table with a field: status(enabled, disabled) and end_date, I have my form where I put a certain end time.
I would like that when reaching this end time, the status field changes to disabled.
is there anything i can do to achieve this ?
create_table "lists", force: :cascade do |t|
t.integer "user_id"
t.binary "uuid", limit: 36
t.string "name"
t.string "description"
t.datetime "end_date"
t.integer "status", default: 1
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id"], name: "index_lists_on_user_id"
end
You can create a method that checks if the end time is the same as current date and then set the status value
def self.update_status
List.where(end_date: DateTime.current).update_all(status: 'disabled')
end
Now you can call this method from the scheduler to run this method every min, every hour, or every day as per your requirement.
Checkout whenever gem which is popular to write scheduled jobs.
every :hour do # Many shortcuts available: :hour, :day, :month, :year, :reboot
runner "List.update_status"
end

Why will a rake file used to seed a datbase not work due to foreign key constraints in Ruby on Rails?

I have created a dummy travel agency with Rails 6 and I am trying to use a rake file to seed data for ships, crusies and customer details etc.
The file: ships.rake looks like this:
namespace :ships do
desc "TODO"
task seed_cabins: :environment do
CreditCard.destroy_all
Address.destroy_all
Customer.destroy_all
Cruise.destroy_all
Ship.destroy_all
p "tables emptied"
5.times do |index|
Ship.create!(name: Faker::Coffee.blend_name, tonnage: Faker::Number.within(range: 10000..100000))
end
p "ships created"
# create cabins for each ship
ships = Ship.all
ships.each do |ship|
5.times do |index|
Cabin.create!(
ship_id: ship.id,
name: "Suite #{index+1}",
beds: Faker::Number.between(from: 1, to: 3),
deck: Faker::Number.between(from: 1, to: 3)
)
end
end
p "Cabins created"
ships = Ship.all
ships.each do |ship|
2.times do |index|
Cruise.create!(
ship_id: ship.id,
name: Faker::Hacker.adjective.capitalize + " " +Faker::Hacker.noun.capitalize+" Cruise"
)
end
end
#create customers
3.times do |index |
Customer.create!(
first_name:Faker::Name.first_name,
last_name:Faker::Name.last_name,
has_good_credit: true,
paid: false
)
end
#give each customer an addresses and credit card
customers = Customer.all
customers.each do | customer|
Address.create!(
street:Faker::Address.street_address,
city:Faker::Address.city,
postcode:Faker::Address.postcode,
customer_id: customer.id
)
year = [2020, 2021,2022, 2023]
organisations =["American Express", "MasterCard", "Visa"]
CreditCard.create!(
customer_id:customer.id,
number:Faker::Number.number(12),
exp_date:year.sample.to_s + "/" + Faker::Number.between(1,12).to_s,
name_on_card: customer.first_name + " " + customer.last_name,
organisation: organisations.sample.to_s
)
end
p "customers created"
end
end
The database schema looks like this:
ActiveRecord::Schema.define(version: 2020_10_27_221059) do
create_table "addresses", force: :cascade do |t|
t.string "street"
t.string "city"
t.string "postcode"
t.integer "customer_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["customer_id"], name: "index_addresses_on_customer_id"
end
create_table "cabins", force: :cascade do |t|
t.string "name"
t.integer "beds"
t.integer "deck"
t.integer "ship_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["ship_id"], name: "index_cabins_on_ship_id"
end
create_table "credit_cards", force: :cascade do |t|
t.string "number"
t.string "exp_date"
t.string "name_on_card"
t.string "organisation"
t.integer "customer_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["customer_id"], name: "index_credit_cards_on_customer_id"
end
create_table "cruises", force: :cascade do |t|
t.string "name"
t.integer "ship_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["ship_id"], name: "index_cruises_on_ship_id"
end
create_table "customers", force: :cascade do |t|
t.string "last_name"
t.string "first_name"
t.integer "has_good_credit"
t.boolean "paid"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "harbours", force: :cascade do |t|
t.string "name"
t.string "country"
t.string "lat"
t.string "long"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "ships", force: :cascade do |t|
t.string "name"
t.integer "tonnage"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
add_foreign_key "addresses", "customers"
add_foreign_key "cabins", "ships"
add_foreign_key "credit_cards", "customers"
add_foreign_key "cruises", "ships"
end
Essentially, I am just try to run the command: rake ships:seed_cabins and try to generate the data fresh. However, I keep getting the following error:
rake aborted!
ActiveRecord::InvalidForeignKey: SQLite3::ConstraintException: FOREIGN KEY constraint failed
/home/jonathon/Projects/waad/RailsApps/travelagent/lib/tasks/ships.rake:8:in `block (2 levels) in <main>'
Caused by:
SQLite3::ConstraintException: FOREIGN KEY constraint failed
/home/jonathon/Projects/waad/RailsApps/travelagent/lib/tasks/ships.rake:8:in `block (2 levels) in <main>'
Tasks: TOP => ships:seed_cabins
(See full trace by running task with --trace)
I am aware the order of when the tables are destroyed is an issue and the current order is the closest I can get to the file working. it seems to be the Ship.destroy_all line that is the issue because when I remove it and run the file it runs with no issues!
However, as far as I can see there would be no constraints left on that database once the other tables are cleared that would prevent Ship from being deleted?
If anyone could point me in the right direction I would be very grateful.
You missed destroying the cabins, which are still referencing the ships as foreign key. Hence the foreign key constraint is kicking in.
On a side note, you can make your life easier by adding dependent: :destroy in your associations. For example, in your Ship model, you would add,
class Ship < ApplicationRecord
has_many :cabins, dependent: :destroy
end
Since a cabin doesn't make sense without the corresponding ship. What this will do is, whenever a Ship instance is destroyed, it will destroy the related cabins as well.

ActiveRecord is not aware of timezones?

I have one question regarding to time zone
I have done the following yet, my activerecord is not still matching with my timezone when I do following query
def stock_by_date(date)
UserStock.where("date(created_at) = ? and user_id = ? ", date , current_user.id)
end
I did the following in side my application.rb
config.active_record.default_timezone = :utc
config.active_record.time_zone_aware_attributes = true
config.beginning_of_week = :sunday
config.active_record.time_zone_aware_types = [:datetime, :time]
I added timezone field to my sign up method, and it shows the current day of timezone correctly, yet when I added a stock for the current day timezone, it shows up in either the previous day or next day of current daytime zone and when I added my stock, the timestamp is for a day before when I look at the rails console
My schema.rb
ActiveRecord::Schema.define(version: 2018_11_28_183416) do
create_table "friendships", force: :cascade do |t|
t.integer "user_id"
t.integer "friend_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["friend_id"], name: "index_friendships_on_friend_id"
t.index ["user_id"], name: "index_friendships_on_user_id"
end
create_table "notes", force: :cascade do |t|
t.string "content"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.index ["user_id"], name: "index_notes_on_user_id"
end
create_table "stocks", force: :cascade do |t|
t.string "ticker"
t.string "name"
t.decimal "last_price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "user_stocks", force: :cascade do |t|
t.integer "user_id"
t.integer "stock_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["stock_id"], name: "index_user_stocks_on_stock_id"
t.index ["user_id"], name: "index_user_stocks_on_user_id"
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "first_name"
t.string "last_name"
t.string "time_zone", default: "UTC"
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
end
for example,
How can I fix this issue?
Note: If more info is needed, please let me know
Note: for the matter of being concise this is my repo
Note: my configuration does not show a reliable behavior at all and I am very confused :/ and I have the same issue for note of a current day
----update-------------------
In my rails console
create a migration with this content to remove the default value to created_at, so it's not filled by default on database level.
change_column_default(:user_stocks, :created_at, nil)
after that, when you create a new UserStock, you need to specify the created_at value, and there you can specify the created_at with the date of the user, taking care of the timezone.
UserStock.create(created_at: Time.now.in_time_zone(user.time_zone).to_time...)
or you can just maybe add it to a callback on the model so it's automatic everytime you create a UserStock, it change the value
class UserStock < ActiveRecord::Base
before_create :set_created_at
private
def set_created_at
self.created_at = time.now.in_time_zone(self.user.time_zone).to_time
end
end
so everytime you create one, the value is correct. with that it may work as expected.
Another option if you don't need it just for that specific model and use them for all the user interaction, you can create a before filter on the application controller to set the time zone dinamically, something like
class ApplicationController < ActionController::Base
before_filter :set_time_zone
def set_time_zone(&block)
time_zone = current_user.try(:time_zone) || 'UTC'
Time.use_zone(time_zone, &block)
end
end
Did you try the query by specifying the range?
Because you're trying to find the user_stocks that are created on some date. But notice that created_at is a datetime object and I guess your date variable might be just a date object.
def stock_by_date(date)
UserStock.where(created_at: date.midnight..date.end_of_day, user_id: current_user.id)
end

How to find trending hashtags based on use case in Ruby on Rails

At first, that is my schema file
create_table "events", force: :cascade do |t|
t.string "title"
t.text "description"
t.string "location"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id"], name: "index_events_on_user_id"
end
create_table "events_hash_tags", id: false, force: :cascade do |t|
t.integer "event_id"
t.integer "hash_tag_id"
t.index ["event_id"], name: "index_events_hash_tags_on_event_id"
t.index ["hash_tag_id"], name: "index_events_hash_tags_on_hash_tag_id"
end
create_table "hash_tags", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
hashtags creating successfully in hash_tags table and creating the association with events_hash_tags.
I want to know how to find the trending hashtags based on use cases like if 10 hashtags on hash_tags table then how to find which hashtag used in most events if one hashtag used in 10 events and that is maximum then how to find that programmatically.
My question is how to find 5 trending hashtags which used maximum time of events.
Perdon if I did not explain well.
Thanks
Another answer from #PatMellon is partially right the reason is #questionnaire said in the comment, below the answer which is the name column is unique and it associated with events_hash_tags.
I think you need to follow the has_many :through Association and counter_cache for counting association.
And then
#trendings = HashTag.limit(5).order(events_hash_tags_count: :desc)
I think it will help
HashTag.all.group('name').count.sort_by {|_key, value| value}.reverse.to_h would give a sorted count of all the hash tags entered in your db. If you add a where query you can limit your search to the day, week, or whatever. If you ran a query like this every hour it would list the most used, or trending, hashtags for that hour.

Rails compound key to enforce uniqueness on the pair of values

I am trying to build a toy application and ran across an issue I cannot seem to solve. How do I enforce that a pair of values are unique in a table?
suppose the following schema:
create_table "courses", force: :cascade do |t|
t.string "title"
t.text "description"
t.string "number"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "status", default: 0
end
create_table "professors", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "status", default: 0
end
create_table "sections", force: :cascade do |t|
t.integer "number"
t.integer "max_enrollment"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "professor_id"
t.integer "course_id"
t.string "room"
t.index ["course_id"], name: "index_sections_on_course_id"
t.index ["professor_id"], name: "index_sections_on_professor_id"
end
and I wanted to create a uniqueness constraint in the sections table that the professor_id paired with course_id must be unique. the only thing I have found in my digging is that you can use the validates keyword in the model to enforce the uniqueness of a single field... I also saw that there is a validates_with keyword but I cannot find any way of writing a validator to do what I'm looking for. any help would be greatly appreciated.
Add a unique constraint in your database (Pun in a migration):
add_index :sections, [:professor_id, :course_id], unique: true
Now also put a validation constraint in your Section model:
validates_uniqueness_of :professor_id, scope: :course_id
Now your professor_id will be uniquely validated in the scope of course_id. Also there will be a unique constraint in your database table.

Resources