Rails Model Validation on :symbol for a date - ruby-on-rails

I'm trying to compare a couple of dates from my form.
Im my validation I have something like:
:mydate - 1.day
But I get:
undefined method `-' for :mydate:Symbol"
Totally a newb question, but I cant figure it out LOL - how do I perform date math on a symbol?
Edit:
OK, so I cant access the params from the controller either, or the form object. I'm using basic restful controllers:
def create
#booking = Booking.new(params[:booking])
etc...
end
and then in my model I want to validate some dates - the end result should be that a Checkin date should be the same as a Checkout date minus the number of nights
So my model:
class Booking < ActiveRecord::Base
def validate
errors.add_to_base "Nights Borked" if :checkin != (:checkout - :nights.day)
end
end
Or I'd like to do something like that but cant.
If I try and access #booking.checkin I get:
undefined method `checkin'
If I try to do
#foo = params[:booking][:checkin]
I get
undefined local variable or method `params' for #<Class:0x103fd1408>
What am I missing here. Something obvious probably lol :)

You can't perform date math on a symbol, because a symbol is merely a more-sophisticated string. It'd not holding a value other than its name. But assuming you have a model with an attribute called mydate:
#object.mydate - 1.day
or if you have a parameter passed in from a form:
params[:mydate] - 1.day
Given your updated code samples, you want to call attributes as self.attribute, like so:
class Booking < ActiveRecord::Base
def validate
errors.add_to_base "Nights Borked" if self.checkin != (self.checkout - self.nights.day)
end
end
The validate method is being called on a booking object already, so you want to call the attributes in that context.

Related

RoR: Update attribute in a model from a unrelated controller

I need to pass a value to attribute in a model from a different controller with no direct relation between them. In the below example I need to update farming_year in the Field Model from the Planting controller.
The Field model:
class Field < ApplicationRecord
has_many :crops
attr_accessor :farming_year
def getting_crops
#crops_list = Crop.select('crops.name').where(field_id: self.id, year: self.get_farming_year) # doesn't get the farming_year
end
def get_farming_year
#farming_year # passing the value directly will work #farming_year=2015!!
end
def farming_year=(val)
#farming_year = val # passing the value directly won't work #farming_year=2015!!
end
end
In the Planting controller:
def new
#field = Field.new
#field.farming_year = session[:working_year]
#field.save
flash.now[:success] = #field.get_farming_year # it works and gives the correct year
end
when I changed the #farming_year in the get_farming_year method to #farming_year=2016, then the code will work and will give the correct Crops records. the flash message in the code above without any change will give the correct year from the model. I think my main issue is passing the farming year from get_farming_year method to getting_crops method.
Hint: the framing year is belong to the Crop not to the Field, so I don't need to add it to the Field table.
Any ideas how to achieve that?
Your code has a number of issues.
attr_accessor
Why are you using an attr_accessor? You should store the value on a model attribute, in the database. If your Field model doesn't already have a farming_year attribute, create a migration to add it to the database by running these commands:
$ rails g migration AddFarmingYearToField farming_year:integer
$ rails db:migrate
If you're running Rails <= 4, use rake db:migrate instead of the second command.
Doing this means you don't need to use attr_accessor, or define getters and setters.
PlantingController#new
This method isn't working for you because you haven't defined the correct methods, and you're not saving the instance.
In your Field model, you've defined a farming_year method, but you haven't defined a farming_year= method, which is what the setter should be. Change your farming_year method definition to farming_year=. Alternatively, use the method I described in 1., then you won't have to.
Make sure you're saving the model object once you're done with it - call Field#save, which returns truthy on success and falsy on failure; or call Field#save!, which returns truthy on success and raises an exception on failure.
The main issue with my code was using attr_accessor which I didn't need it, so, I've replaced "attr_accessor :farming_year" with a class variable "##work_year =''", and updated the getter and setter method as in the below code
The Field model:
class Field < ApplicationRecord
has_many :crops
attr_accessor :farming_year
##work_year =''
def getting_crops
#crops_list = Crop.select('crops.name').where(field_id: self.id, year: farming_year) #now this can request the getter method and get the year
end
def farming_year # getter method
##work_year ||= ''
end
def farming_year=(val) #setter method
##work_year = val
end
end
In the Planting controller:
def new
#field = Field.new
#field.farming_year = session[:working_year]
##field.save NO need for this line
flash.now[:success] = #field.farming_year
end
Thank you all for your kind support:)

rails - calculated column on model issue

I want to create a calculated column on a model, which is not in the database.
class Result < ActiveRecord::Base
attr_accessor :calculated_duration
def calculated_duration
(build_start_time - build_end_time)
end
end
This is what I have, and I am trying to access it like this:
#results = Result.all.order(:build_number)
#results.calculated_duration
I'm getting a no method error:
undefined method `calculated_duration'
Can anyone suggest why?
Because you're calling an instance method on an ActiveRecord::Collection
#result = Result.first
#result.calculated_duration
will work

Check if a date is between two other dates

I have a Model called "Tenant" and it has two Date attributes tenant_from and tenant_until.
I want to write a method that checks if Date.today is between the two dates I mentioned above. I want to do something along these lines:
IF Date.today IS BETWEEN tenant.tenant_from AND tenant.tenant_until DO
...
ELSE
...
Try
if Time.zone.today.between?(tenant.tenant_from, tenant.tenant_until)
# YOUR CODE GOES HERE
else
# YOUR CODE GOES HERE
end
Just for an alternate solution. You can use a Date range and cover? to achieve the same effect.
(tenant.tenant_from .. tenant.tenant_until).cover?(Date.today)
Class Tenant < ActiveRecord::Base
def current? #name this what you want, but keep the question mark, since it returns a boolean
(tenant.tenant_from.to_date .. tenant.tenant_until.to_date).include?(Date.today)
end
end
Now you have model logic on an instance of the model (where it belongs). Your logic is then if #tenant.current?.

How to query Rails / ActiveRecord model based on custom model method?

Disclaimer: I'm relatively new to rails.
I have a custom method in my model that I'd like to query on. The method, called 'active?', returns a boolean. What I'd really like to do is create an ActiveRecord query of the following form:
Users.where(:active => true)
Naturally, I get a "column does not exist" when I run the above as-is, so my question is as follows:
How do I do the equivalent of the above, but for a custom method on the model rather than an actual DB column?
Instead of using the active? method, you would have a scope to help find items that match.
Something like this...
def self.active
joins(:parent_table).where(:archived => false).where("? BETWEEN parent_table.start_date AND parent_table.end_date ", Time.now)
end
And, you should be able to do this
def active?
User.active.exists?(self)
end
If you would like to reuse this scope for the instance test.
An easy way to do this would be by using the select method with your exiting model method.
Users.select{|u| u.active}
This will return an array so you won't be able to use Active Record Query methods on it. To return the results as an ActiveRecord_Relation object, you can use the where function to query instances that have matching ids:
class User < ActiveRecord::Base
def self.active
active_array = self.select{|r| r.active?}
active_relation = self.where(id: active_array.map(&:id))
return active_relation
end
end

question on my helper method using self

I created this helper method. In my view I call it with days_left(duedate). I dont really like my helper. Is it possible to use it with self. Since I dont really know how self is being used. Is it the same as this in java or javascript? What object is it related to? Feel free to tune this method. Thx for your time!
def days_left(duedate)
(if duedate.date == Date.today
"Today"
elsif duedate.date-Date.today < 1
"expired"
elsif duedate.date-Date.today == 1
"Tomorrow"
else
"#{(duedate.date-Date.today).to_i}"
end).to_s.html_safe
end
You might try moving this method to your model.
This would be similar to adding a 'full_name' method to a model with the attributes 'first_name' and 'last_name.' You wouldn't store 'full_name' separately in your database, because that would result in redundant, denormalized data.
For example:
class Employee < ActiveRecord::Base
def full_name
"#{first_name} #{last_name}"
end
end
So you could similarly add the 'days_left' method to your model, which fits there because it's adding a friendlier version of an existing data attribute.

Resources