How to use Ruby's send method without receiver? - ruby-on-rails

I am trying to convert user input à la "6 months" into a Ruby method à la 6.months.
How can this be done?
I keep getting an undefined method 6.months error in line 10.
Thanks for any help.
class Coupon < ActiveRecord::Base
def self.duration_options
["3 years", "2 years", "1 year", "6 months", "3 months", "1 month"]
end
def end_at
if Coupon.duration_options.include?(duration)
method = duration.sub!(' ', '.')
time = Time.zone.now + send(method)
end
time
end
end

Your send is on the object itself, in this case it's self.send(method)
You could do like this
if Coupon.duration_options.include?(duration)
off_set = duration.split(" ")
time = Time.zone.now + off_set.first.to_i.send(off_set.last.to_sym)
end
time

Related

Rails How to give options in date time select

I am trying to implement a datetime_select option for a form. I was using a simple date selector like below before hand but the requirements have changed.
<%= f.datetime_select :ends_at, :start_year => Date.current.year %>
What I want to implement instead is to give users only three options as: "One hour", "Two hours", "Three hours" for selection. The corresponding values for the chosen option sent as POST through the form would be calculated from the time the submit button is pressed.
How can I give these options for the users for a datetime data type ?
Okay you can do something like that:
In your Model define:
TIMER = [{"time"=>"One Hour", "val"=>"1"}, {"time"=>"Two Hours", "val"=>"2"}, {"time"=>"Three Hours", "val"=>"3"}]
In your form use a different select field:
<%= f.select :time_to_end, options_for_select(Model::TIMER.map { |obj| [obj['time'], obj['val']] }) %>
Then in the model allow time_to_end parameter as a attr_accesible.
attr_accessible :time_to_end
Also, add a before save callback to change the ends_at field:
before_save :update_ends_at_field
private
def update_ends_at_field
self.ends_at = Time.now + time_to_end.to_i.hours
end
I didn't tested the code above. Hope you got the idea.
I ended up using
<%= f.select :ends_at, options_for_select(ApplicationHelper::TIMER.map { |obj| [obj['time'], obj['val']] })%>
in the form itself.
Where Timer is defined as:
module ApplicationHelper
TIMENOW = DateTime.now
TIMER = [{"time"=>"Half Hour", "val"=> TIMENOW + 0.5.hour},{"time"=>"One Hour", "val"=> TIMENOW + 1.hour}, {"time"=>"One Day", "val"=> TIMENOW + 24.hour}, {"time"=>"Three Days", "val"=> TIMENOW + 3.day}, {"time"=>"Seven Days", "val"=> TIMENOW + 7.day}]
end
in the ApplicationHelper

Calculate Age and place inside age group by Date of Birth

I'm developing a tournament bracketing app and need to compare some dates together in order to place them in their designated age group. I can't seem to figure out how I would write something like this.
6 - under = 2007-09-01 to present
8 - under = 2005-09-01 to 2007-08-31
10 - under = 2003-09-01 to 20050831
Would it be something like this? and is there a better way to compare the dates to each other.
def age_group
if self.dob <= 20030901
"10"
elsif self.dob <= 20050901
"8"
else self.dob <= 20070901
"6"
end
end
Thank you
You can certainly keep to your age_group method, there's nothing wrong with it. I'd just tweak it like so:
def age_group
if self.dob <= 10.years.ago
"10"
elsif self.dob <= 8.years.ago
"8"
elsif self.dob <= 6.years.ago
"6"
end
end
If you do it like this, you will have to go update the cut-off dates of birth each year. You could calculate the age instead and take it from there:
def age
now = Time.now.utc.to_date
now.year - birthday.year - (birthday.to_date.change(:year => now.year) > now ? 1 : 0)
end
(above from Get person's age in Ruby)
Then define the age group:
def age_group
if self.age <= 10
"10"
elsif ...
etc.
A case statement would work well for this, as it uses === for comparisons.
require 'date'
R10U = (Date.parse("2003-09-01")..Date.parse("2005-08-31"))
R8U = (Date.parse("2005-09-01")..Date.parse("2007-08-31"))
R6U = (Date.parse("2007-09-01")..Date.today)
def age_group(dob)
case Date.parse(dob)
when R6U then "6 - under"
when R8U then "8 - under"
when R10U then "10 - under"
else raise ArgumentError, "dob = '#{dob}' is out-of-range"
end
end
age_group("2006-04-12")
#=> "8 - under"
age_group("2004-11-15")
#=> "10 - under"
age_group("2011-06-01")
#=> "6 - under"
age_group("2002-04-30")
#=> ArgumentError: dob = '2002-04-30' is out-of-range
age_group("2015-06-01")
#=> ArgumentError: dob = '2015-06-01' is out-of-range

How to create multiple records for each day in given quarter?

I have Shift model.
--- !ruby/object:Shift
attributes:
id:
starts_at:
ends_at:
I want to add singelton method to create shifts for each day in given quarter.
class Shift
def self.open_quarter(number, year)
starts_at = "08:00"
ends_at = "08:00"
...
end
end
How to implement that in best way? I want that each shifts starts_at 8.00 am and finish 8.00 am on next day.
def self.open_quarter(number, year)
start_time = Time.new(year, number*3 - 2, 1, 8)
while start_time.month <= number*3 && start_time.year == year
Shift.create{starts_at: start_time, ends_at: start_time += 24.hours}
end
end
make sure to set the correct timezone when using Time.new. Default is current timezone (see docs). You can also use Time.utc.
def self.open_quarter(number, year)
starts_at = "08:00 am"
ends_at = "08:00 pm"
quarter_start = Date.new(year, (number * 3)).beginning_of_quarter
quarter_end = Date.new(year, (number * 3)).end_of_quarter
(quarter_end - quarter_start).to_i.times do |n|
start_shift = "#{(quarter_start + n).to_s} #{starts_at}".to_datetime
end_shift = "#{(quarter_start + n).to_s} #{ends_at}".to_datetime
Shift.create(starts_at: start_shift, ends_at: end_shift)
end
end

RoR - Time.strptime issues

Here is the method in question.
def published_at_setter
self.published_at = Time.strptime("#{#date} #{#time}", "%m/%d/%Y %I:%M %p")
puts " ~~~~~~~~~~~~~~~~~~~ #{#date} #{#time} ~~~~~~~~~~~~~~~~ #{self.published_at}"
end
With #date = "09/11/2012" and #time "01:45 AM" I get this in the webbrick console. WFT?
~~~~~~~~~~~~~~~~~~~ 09/11/2012 01:45 AM ~~~~~~~~~~~~~~~~ 2012-09-11 06:45:00 UTC
When in rails console I get the expected results. "2012-09-11 01:45:00 -0500"
Instead of Time.strptime, you should use Time.zone.parse.
def published_at_setter
self.published_at = Time.zone.parse("#{#date} #{#time}")
puts " ~~~~~~~~~~~~~~~~~~~ #{#date} #{#time} ~~~~~~~~~~~~~~~~ #{self.published_at}"
end

Calculate days until next birthday in Rails

I have a model with a date column called birthday.
How would I calculate the number of days until the user's next birthday?
Here's a simple way. You'll want to make sure to catch the case where it's already passed this year (and also the one where it hasn't passed yet)
class User < ActiveRecord::Base
attr_accessible :birthday
def days_until_birthday
bday = Date.new(Date.today.year, birthday.month, birthday.day)
bday += 1.year if Date.today >= bday
(bday - Date.today).to_i
end
end
And to prove it! (all I've added is the timecop gem to keep the calculations accurate as of today (2012-10-16)
require 'test_helper'
class UserTest < ActiveSupport::TestCase
setup do
Timecop.travel("2012-10-16".to_date)
end
teardown do
Timecop.return
end
test "already passed" do
user = User.new birthday: "1978-08-24"
assert_equal 313, user.days_until_birthday
end
test "coming soon" do
user = User.new birthday: "1978-10-31"
assert_equal 16, user.days_until_birthday
end
end
Try this
require 'date'
def days_to_next_bday(bday)
d = Date.parse(bday)
next_year = Date.today.year + 1
next_bday = "#{d.day}-#{d.month}-#{next_year}"
(Date.parse(next_bday) - Date.today).to_i
end
puts days_to_next_bday("26-3-1985")
Having a swipe at this:
require 'date'
bday = Date.new(1973,10,8) // substitute your records date here.
this_year = Date.new(Date.today.year, bday.month, bday.day )
if this_year > Date.today
puts this_year - Date.today
else
puts Date.new(Date.today.year + 1, bday.month, bday.day ) - Date.today
end
I'm not sure if Rails gives you anything that makes that much easier.
Here's another way to approach this with lesser-known methods, but they make the code more self-explanatory.
Also, this works with birth dates on a February 29th.
class User < ActiveRecord::Base
attr_accessible :birthday
def next_birthday
options = { year: Date.today.year }
if birthday.month == 2 && birthday.day == 29 && !Date.leap?(Date.today.year)
options[:day] = 28
end
birthday.change(options).tap do |next_birthday|
next_birthday.advance(years: 1) if next_birthday.past?
end
end
end
And of course, the number of days until the next birthday is:
(user.next_birthday - Date.today).to_i

Resources