I'm writing an app where I need to compare two :datetime fields and get the difference to display as an "elapsed" time from the start of the record. I think I have my code right, but I keep getting the below error. Can someone tell me what I'm doing wrong?
Error on view:
undefined method `-' for nil:NilClass line 26:
26: <td><%= link_to call.elapsed_time, call %></td>
Call.rb (abbreviated)
before_create :set_dispatched_time
def set_dispatched_time
self.dispatched_time = Time.now
end
def elapsed_time
self.dispatched_time - Time.now
end
My fields in PG are set as :datetime so that I can compute times (I did have them as strings.. ooops) but for some reason it's not calculating. Do I need to call Time.parse first or something like that? I'm not really sure which direction to go. I just want to subtract the dispatched_time field from Time.now
Your self.dispatched_time does not exist according the error message, it is nil. This can be because before_create is call when first time the opject is persisted into the database, and this particular instance is not yet saved.
First try to make sure, that this variable has a value, or assign a default value in case if it is not assigned. E.g.:
def elapsed_time
Time.now - (self.dispatched_time || Time.now)
end
Related
I'm using Rails 3 and failing to submit a form because one of the fields fails to pass validates_presence_of. My model is called dinner, and the field, which is used in conjunction with a datepicker, is called date.
views/dinners/new.html.erb:
<%= f.text_field :date, id: "datepicker" %>
models/dinner.rb:
attr_accessible :date
validates_presence_of :date
dinners_controller.rb:
def create
#dinner = Dinner.new params[:dinner]
if #dinner.save
flash[:notice] = "Dinner created successfully."
redirect_to controller: 'dinners'
else
flash.now[:alert] = #dinner.errors.full_messages.join("<br>").html_safe
render action: "new"
end
end
Whenever I fill out all of the fields, including date, I get the error "Date can't be blank", even though it is not blank. What's going on here?
I've found the answer.
My date column was of type date, and before validation Rails ran .to_date on it. Unfortunately, the datepicker that I use creates dates in the American mm/dd/yy format, which Rails can't handle, so .to_date returned nil. That's why the date failed validation: because it really was nil, even though the POST request was fine.
I chose the easy solution and changed the default date of datepicker, as shown here.
Note: For my version of datepicker, I had to use format instead of dateFormat, and also had to use yyyy-mm-dd instead of yy-mm-dd because Rails String#to_date thinks that the year "13" is literally '0013' and not '2013'.
Note: I was overthinking things when I originally asked this question. The accepted answer is correct for the examples I gave - i.e. you can just pass :value to text_field, however I'd actually been having problems with date_select, which doesn't have a facility to override the value set.
As a result this has now been updated in Rails, so you can set :selected => a_date, and it will work as expected. This will be in Rails 4.
I have a model that can inherit its value from a parent model. It works something like this:
class User < ActiveRecord::Base
attr_accessible :field_name
belongs_to :company
def field_name
if self['field_name'].nil?
company['field_name']
else
self['field_name']
end
end
end
class Company < ActiveRecord::Base
attr_accessible :field_name
end
I then have a form to edit the User, but of course, if the User value is nil, then it populates the form with the value from Company, which is not what I want.
I would like to be able to override the value of the form field, so that if the User value is nil, then the value is empty.
Attempt 1
Ideally I'd be able to do:
<%= form_for #user do |f| %>
<%= f.text_field :field_name, #user['field_name'] %>
<% end %>
But that doesn't work, there doesn't seem to be a mechanism for providing an override value.
Attempt 2
So I thought about creating a second getter/setter:
def field_name_uninherited
self['field_name']
end
def field_name_uninherited=(value)
self['field_name']=value
end
Now I can use <%= f.text_field :field_name_uninherited %> and it works as expected - great! Except: when field_name is a date, or other type using multiparameter attributes, it results in this error:
1 error(s) on assignment of multiparameter attributes
I believe this is because it doesn't know that this is a date field, as it infers this from the database, and this field (with _uninherited suffix) is not in the database.
So I need some way to mark my additional method as the same type as the original database field.
A further note, the above examples (using field_name) are a simplified version. I'm actually using https://github.com/colinbm/inherits_values_from to handle the inheritance, but I don't think this is important to the question.
Obviously if there's a better way to accomplish the same goal, then I'm all ears.
So when it comes to displaying the value you for a user you want it to behave a bit differently?
What I'd do is use the :value option with your form field. That way you get to set the value like normal but choose what you want displayed in the form field.
<%= f.text_field :company, :value => user.field_name_uninherited %>
For what I understand, you want the user to put the field data and only if it's nil, populate that value with the parent (company) model. It seems to me before_save works perfectly, because it is called (as it name proposes) just before the save method is called on an ActiveRecord object.
Thus you can write this kind of callback:
class User < ActiveRecord::Base
attr_accessible :field_name
before_save :override_field
private
def override_field
if self.field_name.nil?
self.field_name = company.field_name
end
end
This way, you'll be only overriding the value if it's nil at the moment of saving, leaving that form field empty at the moment of creating a new element. Hope this works!
Okey i just dont understand what can be wrong here
i have this app where users are approved by and admin and this was working fine until a few days ago
in my view i have a link that calls my user controller
<%= link_to 'Approve', active_user_path(user), :method => :put %>
here is my custum route for that link
match "users/:id/activate" => "users#activate", :as => "active_user"
now in my user controller i have this activate method
def activate
#user = User.find(params[:id])
puts #user.name #the correct name is displayed
puts #user.is_approved.inspect.to_i #:is_approved is 0
if #user.update_attribute(:is_approved, 1)
puts #user.is_approved.inspect # :is_approved is 1
#user.activate_user
puts #user.is_approved.inspect # :is_approved is 1
#user.save!
redirect_to "/users?is_approved=0"
else
render "/" # dosn't matter
end
end
I try to save 3 times here (update, activate_user, save!) but still the value will not be saved, the users is_approved field is still 0, how is that possible ?
here is my model method
def activate_user
self.is_approved = 1
self.save
end
btw i can update strings with this method but not integers (true and false dosnt work either)
in my model i have is_approved as both attr_accessible and attr_accessor
The solution
Well this is awkward but so it happens that in my user model i had attr_accessor :approved this resulted in that the model never went to the database to update the :approved column BUT instead it updated the local variable :approved so next time when i looked at the column then of course the :approved value had not changed
tldr?
if you have attr_accessor in your model with the same name as the column your trying to update => remove it
Never use attr_accessor on an attribute which is backed by a database column - the accessor generated by attr_accessor will mask the value stored in the database
update_attribute actually does more than just updating a single column:
Validation is skipped.
Callbacks are invoked.
updated_at/updated_on column is updated if that column is available.
Updates all the attributes that are dirty in this object.
Are there any callbacks in your User model?
Make sure the column is not being updated somewhere in a callback.
This has got to be extremely simple but I'm banging my head against the wall trying to find an answer. I want to find the last updated record using the instance method shown below.
class Subject < ActiveRecord::Base
has_many :assignments, :dependent => :destroy
def get_last_assignment_date
#last_date = self.assignments.select("date_assigned").last
#last_day = #last_date.wday
end
Where my assignments model looks like this:
create_table "assignments", :force => true do |t|
t.date "date_assigned"
<snip>
But Rails returns the following error for get_last_assignment_date:
undefined method `wday' for #<Assignment date_assigned: "2012-08-30">
I need to convert the value returned by active record to a Time format that Ruby can handle but I can't figure out how to do it and it seems to be so easy that no one has even bothered to write how to do it. I would greatly appreciate it if someone could point me in the right direction.
This:
self.assignments.select("date_assigned").last
returns an Assigment object, not a Time object.
So, instead of:
#last_day = #last_date.wday
you have to do:
#last_day = #last_date.date_assigned.wday
You may be aware of this, but just in case: select("date_assigned").last doesn't give you the latest date. You have to use order:
self.assignments.order(:date_assigned).last
Of course if the most recently created object is also the one with the latest date_assigned then it doesn't matter.
Have a publish_on datetime field.
Just trying to get to the begining_of_week from the publish_on.
Tried a helper
def start_week(publish_on)
DateTime.parse(publish_on).beginning_of_week
end
and in view <%= start_week(#survey.publish_on) %>
Tried in my model
def set_start_week
publish_on.beginning_of_week
end
Hell, even tried this helper
def this_should_work
DateTime.now.beginning_of_week
end
But everything returns a invalid date to my view. It works in irb, why not in my view?
EDIT
module SurveysHelper
require 'date'
require 'time'
def this_should_work
DateTime.now.beginning_of_week
end
end
take_survey.html.erb
<%= this_should_work %>
Error
invalid date
I encountered the same problem when trying to use ActiveSupport outside of Rails. I found the answer here:
http://guides.rubyonrails.org/active_support_core_extensions.html
Here is the key bit:
require 'active_support/all'
Have you customized your rails stack to no longer include ActiveSupport?
In rails 3.0.9 I got
undefined method `at_beginning_of_week'
wherever I put it, my alternative solution is:
def SomeMethodPutAnywhere
...
#datey = Date.today
#monday = #datey - #datey.wday + 1
##monday is now the monday of the current week.
#Remove the constant '+1' if your week begins sunday...
...
end