Ruby on Rails: invalid argument to TimeZone[]: nil - ruby-on-rails

NOTE: This is my first post, so please be kind. I'm a rails newb so it's very plausible that i'm missing something simple.
I'm working with a Ruby on Rails application locally and am getting this ArgumentError when attempting to fill out a test form:
invalid argument to TimeZone[]: nil
Application Trace shows the following:
app/models/venue.rb:117:in `timezone'
app/controllers/events_controller.rb:80:in `block in create'
Lines 116-118 in venue.rb:
def timezone
ActiveSupport::TimeZone.new(timezone_name)
end
Lines 78-87 in events_controller.rb:
["start", "end"].each do |t|
month, day, year = params["event"]["#{ t }_date"].split("/")
#event.send("#{ t }s_at=", #event.venue.timezone.local_to_utc(Time.utc(
("20" + year).to_i,
month.to_i,
day.to_i,
military_hours(t),
params["#{ t }_minute"].to_i,
0
)))
The form works correctly on the live site, so its possible that i setup my dev environment improperly. Can anyone point me in the right direction?
UPDATE
class Venue
key :timezone_name, String
def set_timezone_name
tz = Timezone.contains(self)
self.timezone_name = tz.name if tz
end

It would help if you provided more context for this question. I'll assume that set_timezone_name is called to initialize the timezone_name value when there is none set. It's then likely in this case set_timezone_name fails to set a value. You could try providing a fallback to guarantee a value is set. Example:
def set_timezone_name
tz = Timezone.contains(self)
self.timezone_name = tz.try(:name) || “Eastern Time (US & Canada)”
end

Related

TypeError: no implicit conversion of Fixnum into Hash - Ruby

Did I try google?
Yes, I tried stack overflow, google, rubydocs, bunch of websites but there are minimal results to this and it's only ever mentioned indirectly. So yes, I did a lot of searching.
What's working?
I run the following query:
requests = Request.where("customer_id = ?
AND request_method != ?
AND request_time
BETWEEN ? AND ?",
customer.id, "OPTIONS", start_time, end_time).group('request_time')
As a result I get a bunch of values from the Database which look like this and this is CORRECT:
#<ActiveRecord::Relation[#<Request id: 171792, request_time: "2022-04-04 14:07:20">,
#<Request id: 171787, request_time: "2022-04-04 14:06:02">...]
NOTE: I didn't paste all the values because they have a similar structure.
What's the problem?
After running the query I want to pass it to the variable dates_init_hash = {} and merge it whilst counting into data[:requests]:
dates_init_hash = {}
(start_time.to_date..end_time.to_date).each do |date|
dates_init_hash[date] = 0
end
data[:requests] = dates_init_hash.merge(requests.count)
Unfortunately, I always seem to be getting the error:
ERROR -- : TypeError: no implicit conversion of Fixnum into Hash
Expected
I should be getting a Hash like the following:
{ "2022-03-24"=>2, "2022-03-25"=>1, "2022-03-28"=>3, "2022-03-29"=>11}
What I tried
I tried to convert the results to a hash before passing it over but this gave me the error that the .to_h method doesn't exist
data[:requests] = dates_init_hash.merge({requests: requests.count }) works half-way still causing errors
Questions
Why am I getting a Fixnum and why won't this work? How can I improve this? What would be the right way to solving this? I appreciate any kind of help.
Why is the error happening?
You are getting the error because when you run:
data[:requests] = dates_init_hash.merge(requests.count)
dates_init_hash is a hash, and requests.count is a number. So you are trying to merge a number into a hash, what is not allowed.
How can I fix it?
If what you want is to have the dates_init_hash with a mapping date => number of requests that date, you can do the following:
# initializes dates_init_hash with desired dates
dates_init_hash = {}
(start_time.to_date..end_time.to_date).each do |date|
dates_init_hash[date.iso8601] = 0
end
# iterates over reuests and add 1 to the date in dates_init_hash for each request in the desired date
requests.each do |request|
date = Date.parse(request[:request_time]).iso8601
next if dates_init_hash[date].nil?
dates_init_hash[date] += 1
end
Then, dates_init_hash will be something like
{"2022-04-04"=>1, "2022-04-05"=>0, "2022-04-06"=>1, "2022-04-07"=>0}

Converting a string into a date Ruby on Rails

I'm attempting to convert a string date into a date that can be stored in the database. These are my attempts:
params[:event][:start_date] = '03-21-2016'
DateTime.strptime(params[:event][:start_date], '%Y-%m-%dT%H:%M:%S%z')
or
DateTime.strptime(params[:event][:start_date], '%m-%d-%Y')
However I keep getting an invalid date error. I'm not sure what I'm doing wrong.
One way to do it would be this:
date_string = '03-21-2016'
month, day, year = date_string.split('-').map(&:to_i)
DateTime.new(year, month, day)
You need to understand what each fragment (eg %Y) in the format string ('%Y-%m-%dT%H:%M:%S%z') means: read this.
http://apidock.com/rails/ActiveSupport/TimeWithZone/strftime
Once you know this, you can tailor a format string to the date string you have, or expect to get: in this case, "%m-%d-%Y".
When debugging create a new, basic and simple, version of the code and test that.
require 'date'
params = '03-21-2016'
DateTime.strptime(params, '%m-%d-%Y') # => #<DateTime: 2016-03-21T00:00:00+00:00 ((2457469j,0s,0n),+0s,2299161j)>
Note the order for the format: '%m-%d-%Y', which works. That's the problem with your first attempt, where you tried to use%Y-%m-%d. There is NO month21or day2016`.
Your second attempt is valid but your question makes it appear it doesn't work. You need to be more careful with your testing:
params = {event:{start_date:'03-21-2016'}}
DateTime.strptime(params[:event][:start_date], '%m-%d-%Y') # => #<DateTime: 2016-03-21T00:00:00+00:00 ((2457469j,0s,0n),+0s,2299161j)>

Rails routing - optional parameters not working

I have the code below in my routes.rb file:
get 'page/contact_us(/:year(/:month))'=>'page#contact_us', :as => 'contact_us'
The idea is that entering year and month in the url are optional. But whenever I try to go to the address:
localhost:3000/page/contact_us
I get an error. It's only when I enter both a year and a month that I don't get an error. For example,
localhost:3000/page/contact_us/2014/11
works!
Rails tells me that the error is in the contact_us.html.erb file. The error line is:
<%=contact_us(#month,#year).html_safe%>
The contact_us(month, year) function is defined in a helper file - page_helper.rb
The idea is that 2 arguments are usually passed above (in the url), but sometimes 1 or no arguments may be passed in the url. I get an error when less than 2 arguments are passed.
Please help! I'm using rails 4.1.8 and Rubymine
Your invalid date error is coming from the calendar method that you included a link to you in your comments. You have:
def calendar(month, year)
current_date = Date.new(year, month, 1)
...
The problem is that if month or year is nil, you are basically doing this (in this case, assuming both are nil):
current_date = Date.new(nil, nil, 1)
Just run rails console and try that: you get this error - TypeError: no implicit conversion from nil to integer.
So the problem isn't with your url, its before. You could add some lines like this to fix that error:
def calendar(month, year)
month ||= 1
year ||= 1900
current_date = Date.new(year, month, 1)
...
...but then you'll have to keep track of the fact that those aren't correct dates so that they don't get passed in the url, wherever that happens.

RSpec - expected equal?( Time Object ) to return true, got false

I'm trying (and failing!) the following code to compare two Time objects in RSpec:
describe '#current_shift_datetime' do
subject { WipStack.current_shift_datetime }
it "To be a Time object" do
expect(subject).to be_kind_of(Time)
end
it "To return current shift datetime" do
# Trying to figure out why they are not equal
puts subject.in_time_zone.round
puts 0.day.ago.midnight.in_time_zone.round
# Problematic code here -->
expect(subject.in_time_zone.round).to be_equal(0.day.ago.midnight.in_time_zone.round)
# End of problematic code
end
end
I have read a couple of things in the internet about rspec time comparisong, one of them explaining the problem with the milliseconds (therefore the round) and another page talking about stub but then i ended with An error occurred in an after hook SystemStackError: stack level too deep.
The ouput of the test is:
1) WipStack#current_shift_datetime To return current shift datetime
Failure/Error: expect(subject.in_time_zone.round).to be_equal(0.day.ago.midnight.in_time_zone.round)
expected equal?(Mon, 17 Feb 2014 00:00:00 CST -06:00) to return true, got false
The puts output:
#current_shift_datetime
To be a Time object
2014-02-17 00:00:00 -0600
2014-02-17 00:00:00 -0600
To return current shift datetime (FAILED - 1)
Update:
Here is the current_shift_datetime method:
def WipStack.current_shift_datetime(scope = nil)
shifts = WipStack.get_shifts(scope)
current_shift = (Time.zone.now - 1.day).strftime("%m/%d/%Y")+" "+shifts.last
current_time = Time.zone.now.strftime("%H:%M")
shifts.each do |shift|
if current_time > shift
current_shift = Time.zone.now.strftime("%m/%d/%Y")+" "+shift
end
end
Time.zone.parse(current_shift)
end
Rather than compare the time zones directly (and get bogged down in subtle differences), you could try comparing the string representations to each other, since that's what you're checking with in the console anyhow.
Depending on how you use this timezone in your app, this should be sufficient to say they are essentially the same time.
expect(subject.in_time_zone.round.to_s).to eq(0.day.ago.midnight.in_time_zone.round.to_s)
You could probably drop the .round if you wanted to as well.
EDIT
Try changing your code so there is no difference between what is printed and what is compared:
it "To return current shift datetime" do
a = subject.in_time_zone.round.to_s
b = 0.day.ago.midnight.in_time_zone.round.to_s
puts a
puts b
expect(a).to eq(b)
end
I fixed it thanks to tyler! It seems that be_equal was actually trying to see if both objects were the same (a comment appear on the test failing when comparing the strings), changing be_equal to eq made the test pass!
it "To return current shift datetime" do
#pending
puts subject.in_time_zone.round.to_s
puts 0.day.ago.midnight.in_time_zone.round.to_s
expect(subject.in_time_zone.round.to_s).to eq(0.day.ago.midnight.in_time_zone.round.to_s)
end

Disable rails class_caching mechanism for Time.now?

I'm currently fighting with the rails class_caching mechanism as I need to return a file path that changes discrete over time. It is used to constantly change a log file path after the amount of GRAIN seconds and returns a fully working timestamp:
GRAIN = 30
def self.file_path
timestamp = (Time.now.to_i / GRAIN) * GRAIN
return FILE_DIR + "tracking_#{timestamp.call}.csv"
end
This works really great if the class_caching of rails is set to false. But of course the app is to run with enabled class caching. And as soon as I enable it, either the timestamp variable is cached or the Time.now expression.
I tried to solve this with a proc block, but no success:
def self.file_path
timestamp = Proc.new { (Time.now.to_i / GRAIN) * GRAIN }
return FILE_DIR + "tracking_#{timestamp.call}.csv"
end
Is there anything like a cache disabled scope I could use or something like skip_class_caching :file_path? Or any other solutions?
Thank you for your help!
It's not entirely clear where your code is located, but ActiveRecord has an uncached method that suspends the cache for whatever is inside its block.
I found the problem. Not the Time.now was beeing cached but a logger instance. It was assigned in another method calling the file_path.
As long as the class caching was disabled the environment forgot about the class variable between the requests. But as soon as it was enabled the class variable stayed the same - and desired value - but never changed.
So I had to add a simple condition that checks if the file_path changed since the last request. If so, the class variable is reassigned, otherwise it keeps the same desired value.
I changed from:
def self.tracker
file_path = Tracking.file_path
##my_tracker ||= Logger.new(file_path)
end
to:
def self.tracker
file_path = Tracking.file_path
##my_tracker = Logger.new(file_path) if ##my_tracker.nil? or Tracking.shift_log?(file_path)
##my_tracker
end
Thank you for your help anyways!

Resources