I'm trying to change a 'time' entry with the date entered in the 'date' entry. So if the time is "2000-01-01 10:00:00 UTC" and the date is "2021-10-10" I want the output to be "2021-10-10 10:00:00 UTC".
I almost have it working, however; when I assign the updated date back to the original object, it does not save the change. For instance, in the code below, event_time contains the proper time I want, however, assigning it to #event.time and then printing #event.time shows the change did not take place.
def create
#event = Event.new(event_params)
event_date = #event.date
event_time = #event.time.change(:year => event_date.year, :month => event_date.month, :day => event_date.day)
puts event_time # prints 2021-10-22 06:06:00 UTC
#event.time = event_time
puts #event.time # prints 2000-01-01 06:06:00 UTC
if #event.save
redirect_to(events_path)
else
render('new')
end
end
Any suggestions? I'm new to Ruby so I'm probably missing something obvious here
Here's my schema
create_table "events", force: :cascade do |t|
t.date "date"
t.string "description"
t.boolean "isMandatory"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.string "name"
t.time "time"
t.string "location"
end
You can refer to the SO answer here
The problem is that there is no time-of-day class in Ruby or Rails. All the time classes are dates or timestamps (i.e. date plus time of day).
Inside the database it will be a time (without timezone) column and it will behave properly inside the database. However, once the time gets into Ruby, ActiveRecord will add a date component because there is no plain time-of-day class available, it just happens to use 2000-01-01 as the date.
Everything will be fine inside the database but you'll have to exercise a little bit of caution to ignore the date component when you're outside the database in Rails.
Use datetime column type to hold a date and time. Only use time in the migration if you don't need the date (only want to store time part).
Related
I am trying to add a date of birth to each patient in my database and having issues adding a date to the dob attribute on each patient. When I add for ex. Patient.first(dob: "01/25/1990") I get an error reading no implicit conversion of Integer into Hash. Any ideas on how I would do so?
create_table "patients", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.integer "age"
t.date "dob"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
When I seeded my database, my dob field was nil
I have also tried Patient.first(dob: Date.parse('31-12-2010')) and still get the same error.
You have two problems:
first doesn't take query arguments.
Your date format is ambiguous.
The first finder method looks like:
first(limit = nil)
Find the first record (or first N records if a parameter is supplied). If no order is defined it will order by primary key.
You want to use find_by as your .where(...).first shortcut.
And to avoid ambiguity with your dates, you should use Date objects or ISO-8601 formatted strings (i.e. YYYY-MM-DD) inside the application and leave the supposedly "human friendly" formats for the very edges.
You want to say:
Patient.find_by(dob: '1990-01-25')
For the sake of explanation, I'm writing an app where a User can log their expenses.
In the User's show view, I want to only show the User's expenses from the current month.
My expenses table looks like this:
create_table "expenses", force: :cascade do |t|
t.date "date"
t.string "name"
t.integer "cost"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
end
The date field is in the date format, so looks like: Thu, 14 Apr 2016
In my controller, I've got something like:
def show
month = Date.today.strftime("%m")
#user = User.find(params[:id])
#expenses = Expense.where(:user_id => #user.id, :date => month)
end
Obviously, this isn't going to work, but it will be something along these lines, I'm guessing?
Any help would be great, thanks!
Usually you can tackle it this way:
Expense.where(date: (Date.today.beginning_of_month..Date.today.end_of_month))
Where that defines a range that can be used as a BETWEEN x AND y clause.
If this is a common operation you might want to express the date as a separate column in YYYYMM format so that these are easily retrieved.
If you're using MySQL, you can use the extract function, to create a .where like:
def show
month = Date.today.strftime("%m")
year = Date.today.strftime("%y")
#user = User.find(params[:id])
#expenses = Expence.where('extract(month from `date`) = ? AND extract(year from `date`) = ? AND `user_id` = ?', month, year, #user.id)
end
Havent tested, although it should work.
Sources:
https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html
My Schedule model looks like this:
create_table "schedules", force: :cascade do |t|
t.integer "week_day"
t.time "opening_time"
t.time "closing_time"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "taco_place_id"
end
add_index "schedules", ["taco_place_id"], name: "index_schedules_on_taco_place_id"
As you can see, there are opening_time and closing_time properties and I have a realtionship Schedule belongs_to :taco_place and TacoPlace has_many :schedules, dependent: :destroy.
What I am trying to do from the Schedule model is to get the actual schedule for a TacoPlace for today (if it exists).
I have already implemented a scope for having today's schedules for a TacoPlace (depending on the week_day property) that looks like this:
scope :today_for_taco_place, ->(taco_place){where(taco_place_id: taco_place.id, week_day: Time.now.wday)}
and I'm using it in this method:
def self.actual_for_taco_place(taco_place)
today = self.today_for_taco_place(taco_place)
today.where("opening_time <= :now and closing_time >= :now", now: Time.now.utc).first
end
I have tested it and it "works". The thing is that if I run "Schedule.first.opening_time" on the console I get "2000-01-01 06:00:00 UTC". As you can see, it does not only include the time, but also the day (even if it was seeded as "opening_time: "15:00".to_time, closing_time: "24:00".to_time").
Finally, here is the question:
Is there a way that I can run something like this: (I know this won't work yet)
def self.actual_for_taco_place(taco_place)
today = self.today_for_taco_place(taco_place)
today.where("#{opening_time.strftime("%H%M")} <= :now and #{closing_time.strftime("%H%M") >= :now", now: Time.now.utc.strftime("%H%M")).first
end
So that the .where() method doesn't look for the property (opening_time or closing_time), but rather perform the strftime() method so I can compare the time only? Or should I save the opening_time and closing_time as integers (i.e. "1200") or manually convert them in a method?
Sorry if my question was long or hard to understand. Thank you in advance for your advise.
Opening_time and closing_time are now integers. I figured out that I don't gain anything from it being a "time" instead of an "integer" since it is only representing an hour.
My database schema includes a time field:
create_table "my_model", force: true do |t|
t.time "at"
t.datetime "created_at"
t.datetime "updated_at"
end
I've tried to query it with something like this:
MyModel.where(at: Time.now)
The problem is that will never return anything even though a record exists with the same hour, minute and seconds as right now, because Time.now includes the year, month and day. At least I think that's why it never returns back anything?
How do I query MyModel's at field?
I think is too late now but you can do this:
timenow = Time.now
MyModel.where(at: timenow.strftime("%I:%M%p"))
I have just changed a column (called time) from t.string to t.datetime and then dropped and re-created the database and run the migration.
I have a script set to run every minute that scrapes information from a remote website and then adds the information to new records based on the time column that I adjusted to be a datetime rather than string.
# Add each row to a new call record
page = agent.page.search("table tbody tr").each do |row|
next if (!row.at('td'))
time, source, destination, duration = row.search('td').map{ |td| td.text.strip }
call = Call.find_or_create_by_time(time)
call.update_attributes({:time => time, :source => source, :destination => destination, :duration => duration})
end
Since changing the time column to integer the script doesn't seem to be importing any information at all. I wondered if there is an extra step that I need to do to make this work again?
My schema looks like this:
create_table "calls", :force => true do |t|
t.string "source"
t.string "duration"
t.datetime "time"
t.string "destination"
t.string "recording"
t.string "cost"
t.datetime "created_at"
t.datetime "updated_at"
end
In this part
time, source, destination, duration = row.search('td').map{ |td| td.text.strip }
call = Call.find_or_create_by_time(time)
you get time variable as a string, and trying to find_by it. I think smth like
call = Call.find_or_create_by_time(Time.parse(time))
should do the trick