How to test 14 day timeframe on user creation? - ruby-on-rails

I'm trying to build a trial period checker and I'm trying to test whether a user was created inside the 14 day period. So if its outside 14 days then I get a false. Thoughts?
if #user.trial_period === true
trial_users = User.where(created_at:14.days.ago..Time.current.end_of_day)
#trial_check_user = trial_users.where('id = ?', current_user.id)
if #trial_check_user.first.present?
#user_in_trial = true
puts "!!!!!!! USER STILL IN TRIAL WINDOW !!!!!!!".red
else
#user_in_trial = false
puts "!!!!!!! NOT IN TRIAL NEED SUBCRIPTION !!!!!!!".red
redirect_to new_subscription_path
end

if current_user.created_at > 14.days.ago
# Still in trial
#trial_check_users = User.where('created_at > ?', 14.days.ago).count
else
#trial_check = false
redirect_to new_subscription_path
end

Related

rufus gem how to keep one job running while stopping the other

This is my scheduler.rb in my initializer file
unless defined?(Rails::Console) || File.split($0).last == 'rake'
s = Rufus::Scheduler.singleton
s.every '1m', :tag => 'main_process' do
Rails.logger.info "hello, it's #{Time.now}"
Rails.logger.flush
Bid.all.each do |bid|
id = bid.event_id
puts "*" * 50
puts bid.id
puts bid.event_id
puts "*" * 50
# #price = BuyNowBid.find_by(bid_id: params[:bid_id])
#events = Unirest.get("https://api.seatgeek.com/2/events/#{id}?&client_id=NjQwNTEzMXwxNDgxNDkxODI1").body
if #events["stats"]
#low = #events["stats"]["lowest_price"] || 0
#avg = #events["stats"]["average_price"] || 0
BuyNowBid.create(bid_id: bid.id, lowest_price: #low , average_price: #avg)
if #low <= bid.bid
send_message("+13125501444", "Lowest price matched! Buy your ticket now!")
bid.bid = 0
bid.save
end
else
puts 'problem with #events?'
p #events
end
end
end
end
def send_message(phone_number, alert_message)
account_sid = ""
auth_token = ""
#client = Twilio::REST::Client.new account_sid, auth_token
#twilio_number = ""
message = #client.messages.create(
:from => #twilio_number,
:to => phone_number,
:body => alert_message
)
puts message.to
end
so I'm running a job to pull the lowest price every minute from an api and when the lowest price matches a bid someones placed they receive a text notification, which works although, the problem I'm having is i want the job to keep running where ever minute I'm pulling the lowest price from api, but i don't want the user to keep getting the same text notification every minute.
Right now I have it so this doesn't happen but after a bid is matched it is essentially deleted from the database. so basically I'm asking how can I keep scraping the api every minute for the lowest price bid match but only send one text to the user notifying them of the bid match and to not have to delete that bid from the database.
I was really over thinking this i just created a new column called saved bid on my bid table and set that equal to bid.bid before it became zero
#events = Unirest.get("https://api.seatgeek.com/2/events/#{id}?&client_id=NjQwNTEzMXwxNDgxNDkxODI1").body
if #events["stats"]
#low = #events["stats"]["lowest_price"] || 0
#avg = #events["stats"]["average_price"] || 0
BuyNowBid.create(bid_id: bid.id, lowest_price: #low , average_price: #avg)
if #low <= bid.bid
send_message("+13125501444", "Lowest price matched for #{#events["title"]} ! Buy your ticket now for #{bid.saved_bid}!")
**bid.saved_bid = bid.bid**
bid.bid = 0
bid.save

Rails devise after_sign_in first time, check attribute and update another user one time

After a user's first sign in, I want to see if another user referred them by the referral_code_used column, and increase that user's referral_count + 1. Currently, a user is logged in and is taken to home_path
I have tried writing an after_sign_in_path_for(resource) method. This gets the job done, with respect to the referral count. The issue is this takes the user to users/:id path instead of home.
def after_sign_in_path_for(resource)
if resource.sign_in_count > 1
puts "sign in count is greater than 1"
elsif resource.sign_in_count === 1
puts "sign in count is 1"
if resource.referral_code_used != nil
referral_code = resource.referral_code.strip
length = referral_code.length
referral_code = referral_code[5..length]
#user_referral_code = referral_code.to_i
if User.exists?(id: #user_referral_code)
referral_user = User.find_by_id(#user_referral_code)
referral_user.referral_count = referral_user.referral_count + 1
referral_user.save
end
end
puts "signin count = 1"
end
#redirect_to home_path
end
When I put in a redirect_to home_path, it says Render and/or redirect were called multiple times in this action. I'm guessing this is in the new sessions controller, which is handled by devise, but am unsure about that.
When I put it in the application controller, like below, there are no routing issues, but it calls it multiple times and adds more than 1 to referral_count:
before_action :check_referral_code
def check_referral_code
if user_signed_in?
if current_user.sign_in_count > 1
puts "sign in count is greater than 1"
elsif current_user.sign_in_count === 1
puts "sign in count is 1"
if current_user.referral_code_used != nil
referral_code = current_user.referral_code_used.strip
length = referral_code.length
referral_code = referral_code[5..length]
#user_referral_code = referral_code.to_i
if User.exists?(id: #user_referral_code)
referral_user = User.find_by_id(#user_referral_code)
referral_user.referral_count = referral_user.referral_count + 1
referral_user.save
end
end
puts "signin count = 1"
end
end
end
relevant routes:
devise_for :users, controllers: { registrations: "users/registrations" }
resources :users
get 'profile/home', to: 'profile#home', as: 'home'
What is the correct way to check the referral_code_used on first sign in, and credit the other user one time? Thanks!
try replacing redirect_to home_path with home_path
def after_sign_in_path_for(resource)
if resource.sign_in_count > 1
puts "sign in count is greater than 1"
elsif resource.sign_in_count === 1
puts "sign in count is 1"
if resource.referral_code_used != nil
referral_code = resource.referral_code.strip
length = referral_code.length
referral_code = referral_code[5..length]
#user_referral_code = referral_code.to_i
if User.exists?(id: #user_referral_code)
referral_user = User.find_by_id(#user_referral_code)
referral_user.referral_count = referral_user.referral_count + 1
referral_user.save
end
end
puts "signin count = 1"
end
home_path
end

Increment/decrement integer in user model by 1

I have a user model which has these columns - name, email, books_on_loan
I have a booking system where users can check out/in books. When A user checks a book out I want to increase their 'books_on_loan_ integer by one, and vice versa.
So far I have tried it like this and am getting an error "undefined method `+' for nil:NilClass" - it doesnt like the #user.books_on_loan
def check_out
#params = params[:book]
title = #params[:title]
name = #params[:name]
#book = Book.find_by_title(title)
#user = User.find_by_name(name)
if #user == nil
#note = 'This user is not registered.'
elsif #book == nil
#note = 'This book is not in the library.'
elsif #book.onloan == 1
#note = 'This book is on loan.'
elsif #user.books_on_loan == 3
#note = 'This user already has 3 books out.'
else
#book.onloan = 1
#book.save
#books_loaned = BooksOnloan.create(book_id: #book.id, user_id: #user.id)
#books_loaned.save
#user.books_on_loan = #user.books_on_loan + 1
#user.save
#note = 'The book was checked out.'
end
respond_to do |format|
format.html
end
end
Try this:
#user.increment :books_on_loan, 1
You can try with following codes, that will handle nil value for #user.books_on_loan
#user.books_on_loan = #user.books_on_loan.to_i + 1
or
#user.books_on_loan = (#user.books_on_loan || 0) + 1
or
#user.books_on_loan = (#user.books_on_loan.present? ? #user.books_on_loan : 0) + 1
While most answers here are ok, you'd rather change the root of the problem otherwise you'd have to use guard causes in your whole app.
It seems books_on_loan to be an attribute in db, so do :
change_column :users, :books_on_loan, :integer, default: 0
#and change existing bad data
User.update_all({books_on_loan: 0}, {books_on_loan: nil})
Or you could change the getter in your class:
def books_on_loan
super || 0
end
Side note, design wise, its not that a good idea to have an integer in db maintaining the current books on loan: you could loose sync the real ones.
You'd rather count a real association.
Simply do #user.books_on_loan.to_i. The to_i will convert nil into 0 automatically
ost answers are very correct but I'd like to add the following.
To answer your question, incrementing the value of an attribute (even on a variable that returns nil) can be done this way:
#user.books_on_loan =+ 1
decrementing being: #user.books_on_loan =- 1
However, you can leverage the benefit of proper model associations here and have a has_many -> through relationship between User and Book where by adding/removing a book for a user, the counter is adjusted accordingly.
Rails provides practical abstraction that you can use: increment and decrement.
So you could now do something like this:
#user.increment(:books_on_loan, 1)
Increment takes 2 argument. The table column and the number by which you increment. It initializes the attribute to zero if nil and adds the value passed as by (default is 1).
Similarly you can use
#user.decrement(:book_on_loan, 1)
More on this HERE

How to come back to previous day?

On my activeadmin, i have to give hours of opening and closing to each shop.
For example, when a shop is open from 09 pm to 04 am, it's recorded as the same date.
But my algorithm has a malfunction
My algorithm is:
def opened?
today_day = Date.today.wday
yesterday_day = today_day == 0 ? 6 : (today_day - 1)
opening = self.openings.where(day: [today_day, yesterday_day]).first
if opening
opening_day = (Time.now).day
if opening.closes_at < opening.opens_at
opening_day = yesterday_day
end
# binding.pry
today_opens_at = Time.new((Time.now).year, (Time.now).month, opening_day, opening.opens_at.hour, opening.opens_at.min)
today_closes_at = Time.new((Time.now).year, (Time.now).month, (Time.now).day, opening.closes_at.hour, opening.closes_at.min)
if today_opens_at < (Time.now) && (Time.now) < today_closes_at
true
else
false
end
else
false
end
end
I try to add gem activesupport for '1.day' but i have an error 'argument out of range'
I don't find the solution, can you help me quickly please?
yerderday_day has to be a day of the month (0..30)
today_day_of_week = Date.today.wday
yesterday_day_of_week = today_day_of_week == 0 ? 6 : (today_day_of_week - 1)
opening = self.openings.where(day: [today_day_of_week, yesterday_day_of_week]).first
yesterday_day = Date.today.prev_day.day
or just replace this block:
if opening.closes_at < opening.opens_at
opening_day = Date.today.prev_day.day
end

Rspec instance variables and controller testing

I'm writing a bowling score calculator, and I'm trying to set up RSpec tests, but for some reason I can't get my tests to work correctly.
players_controller_spec.rb:
require 'spec_helper'
describe PlayersController do
let(:player_names) { ["player1",
"player2",
"player3",
"player4"] }
describe "POST bowl" do
before(:each) do
#game = Game.create!
player_names.each do |name|
Player.create!(:name => name)
end
#game.players = Player.all
Player.all.each do |player|
(0..9).each do |number|
player.frames << Frame.create(:number => number)
end
end
end
describe "for the player's third bowl" do
before(:each) do
#game.players[#game.current_player].frames[9].update_attributes({:number => 9, :first_bowl => "X", :second_bowl => "X", :score => 20})
#game.update_attributes({:current_player => 0, :current_frame => 9})
end
describe "if the bowl is a number score" do
before(:each) do
post :bowl, {:score => "5", :id => #game.id}
end
it "should update the player's score" do
#game.players[#game.current_player].frames[#game.current_frame].score.should == 25
end
end
end
end
end
players_controller.rb
def bowl
#game = Game.find(params[:id])
#score = params[:score]
#current_player = #game.current_player
#current_frame = #game.current_frame
#player = #game.players[#current_player]
#frame = #player.frames[#current_frame]
if #frame.first_bowl.nil?
#frame.first_bowl = #score
if #score == "/"
raise "Error"
end
if #score == "X" && #frame.number == 9
#frame.bonus = 2
end
#frame.score = (/\A[0-9]\z/ === #score ? #score.to_i : 10)
elsif #frame.second_bowl.nil?
#frame.second_bowl = #score
if #frame.score + #score.to_i > 10
raise "Error"
end
if #score == "X"
if #frame.number != 9 || (#frame.number == 9 && #frame.first_bowl != "X") # can't be a spare has to be number or strike
raise "Error"
end
end
if #score == "/" && #frame.number == 9
#frame.bonus = 1
end
if /\A[0-9]\z/ === #score
#frame.score += #score.to_i
elsif #score == "/"
#frame.score = 10
elsif #score == "X"
#frame.score = 20
end
elsif #frame.third_bowl.nil?
#frame.third_bowl = #score
if #frame.number != 9
raise "Error"
end
#frame.bonus = nil
#frame.update_attributes({:score => (/\A[0-9]\z/ === #score ? #frame.score + #score.to_i : #frame.score + 10)})
else
raise "Error"
end
#frame.save
if #game.current_frame > 0
#prev_frame = #player.frames[#frame.number-1]
if #prev_frame.nil?
#prev_frame = Frame.create(:number => #game.current_frame-1)
#player.frames << #prev_frame
#player.frames = #player.frames.sort_by { |f| f.number }
end
update_scores
end
The spec in question is players_controller_spec.rb and at the start of the tests I'm creating a new game with 4 players and each player with 10 frames. Before each test, I'm setting a certain frame's values to be fit what I'm trying to test. The test above is an example where I want to make sure that bowling a score of 5 on the third bowl on the last frame correctly updates the score. But, even though in the debugger I see that the score is updated in the frame (when I debug in the controller method), once I return to the Rspec test, it doesn't work. It expects 25 but gets nil. Is there something I'm missing about how instance variables are transferred between specs and controllers?
So first off there is no 'transferring'. The controller and the example are 2 completely independent objects, each with their own instance variables (You can use the assigns spec helper to retrieve the value of a controller instance variable though).
That's not the root cause of your issue. You do, even before the controller executes, have an #game instance variable that is the game you are interested in. However with activerecord, every time you do Game.find you'll receive separate ruby objects (corresponding to the same database row). Once the row has been loaded from the database it doesn't notice changes made to the database behind its back.
You can reload the object with #game.reload
As a side note this sort of stuff is easier to work with if most of that logic was pushed down into one of your models rather than sitting in the controller.

Resources