Rails filter by date with MetaSearch - ruby-on-rails

I have some records which I show in a view. They have start_date and end_date.
When I access the view, by default I want it only to show records who's dates are not expired.
Expired being defined as:
End date and start date <= Now, and
End date is later than the start date
I then want to have a checkbox that shows all records including the ones that have been expired.
How do I approach this?

In your controller action, you want to have this somewhere:
params[:search] ||= {} # make sure this is instantiated
# filter to show the expired records
if params[:include_expired] # check if the checkbox is checked
params[:search][:end_date_lte] = Date.today # end_date <= Now
params[:search][:start_date_lte] = Date.today # end_date <= Now
end
#records = params[:include_expired] ? RecordClass.where("end_date > start_date").search(params[:search]) : RecordClass.search(params[:search])
You could also bypass all the search things and just use a scope like this:
#records = params[:include_expired] ? RecordClass.expired : RecordClass.all # or whatever logic you need
# scope in the RecordClass
scope :expired, where("end_date > start_date AND end_date <= ?", Date.today)

Related

Rails 4 - How to get specific records based on where conditions

I have a Sale model with an :offer_end column with a date data type. I would like to display specific records of Sale where :offer_end >= Date.today. I tried to get this to work in the controller but im not sure what is the correct syntax to achieve this. This is what im currently doing which isnt working:
def index
#shops = Shop.all
#sales = Sale.where("offer_end >= Date.today", {offer_end: params[:offer_end]})
end
First of all you can't pass the Date.today as a string to the query, it will be passed to the database and it won't understand it.
The query should be something like this
#sale = Sale.where('offer_end > ?', Date.today)
The Date.today will be evaluated then passed as a value to the query.
You could replace the Date.today with any date object or date string, which in your case seems to be in theparams[:offer_end]
#sale = Sale.where('offer_end > ?', params[:offer_end])
You can use scope for these type of operations:
class Sale < ActiveRecord::Base
scope :get_products, ->(date){where(" sales.offer_end >= ? ", date)}
end
In controller you can use this scope as below:
#sales = Sale.get_products(params[:offer_end])
or you can use it directly in controller:
#sales = Sale.where("offer_end >= ?", Date.today)
and you can use params[:offer_end] instead of Date.today

Display all the records when due date is less than current date in Rails

I am having a Quote model which consists of due_date and other fields.
I need to write a condition where we have to display all the records where due_date (which is date data type and stored in database as yyyy-mm-dd format) is less than current date.
For example, current_date is today's date, so I need to display all the records till yesterday.
I wrote a condition but didn't work, can you tell me where I went wrong?
def past_quotes
#items = []
current_date = Time.now.strftime("%Y-%m-%d")
daily_items = Quote.by_account(#account).active.includes(:company).where('due_date' < current_date)
#items << Item.new(items: daily_items) unless daily_items.empty?
end
But still displaying all the records, I think condition is wrong.
You shouldn't use a string when comparing the dates. ActiveRecord should be able to handle dates directly
daily_items = Quote.by_account(#account).active.includes(:company).where('due_date < ?', Date.today)
Can you try following query:
def past_quotes
#items = []
daily_items = Quote.by_account(#account).active.includes(:company).where('due_date < DATE(?)', Time.now)
#items << Item.new(items: daily_items) unless daily_items.empty?
end

Rails Date Query for setting Expiration

I'm creating a marketplace app where sellers can list items to sell. I want to set an expiry date so listings over 30 days old do not show on the site.
I found some similar examples online but can't get this query to work.
#listings = Listing.where('created_at <= ?', Date.created_at + 30.day)
You want to query items whose created_at time is >= the current date (Date.current) - 30 days (30.day). So the query should simply be:
#listings = Listing.where('created_at >= ?', Date.current - 30.day)
You can also replace Date.current with Time.now or DateTime.now.
UPDATE: as user3334690 mentioned in a comment, it's recommended that you make this a model method since it's something that should be in the Model layer:
# app/models/listing.rb
def self.not_expired
where('created_at >= ?', Date.current - 30.day)
end
# now in controllers you can do something like
#listings = Listing.not_expired

Validate Date in Rails before it hits the database

I need to validate two dates in date time format that come from create new record form. Right now the form has drop downs for year, date, month, hour, minute. In the controller, I need to validate that the start date is not greater than end date and it will not let me compare it using the params[:start_date] > params[:end_date].
How can I properly validate that the start date is not larger than the end date when adding a new record to the database, I should be doing this in the model but I cannot figure out how you do it. Does anyone here has any examples I can look from?
Add custom validation to your model to verify that the start date is less than the end date. Something like this would work:
# app/models/my_model.rb
validate :dates_in_order
def dates_in_order
errors.add(:start_date, "must be before end time") unless start_date < end_date
end
#some_model.rb
before_create -> {
errors.add(:base, "Start date cannot be later than end date.") if start_date > end_date
}
Not what you're asking for, but may also be a way to handle this. People sometimes don't read the labels so closely.
before_create :confirm_dates_in_order
def confirm_dates_in_order
start_date, end_date = end_date, start_date if start_date > end_date
end

Rails 3: How to merge queries or scopes for complex query?

I'm building an events app that is very simple, it has a title and start_date and end_date. I would like to filter my query by mixing some of the values, like: if the start_date has passed but the end_date has not, the event is active and should be displayed. If both dates have passed, it should be omitted, too. I think that scopes is the aswer, but I only was able to filter the records within the view using some methods shown below.
I really would like to filter the query that is passed to the controller (#events). I want to show all events that are active, have a future start_date, or a past start_date but are still in progress (Today's date is in range between start_date and end_date)
EDITED
I have made some scopes which return each part of the query. Chaining them actually substracts the results instead of merging them. So i have used this code and actually works do I do not know how solid or DRY this is. Looks kind of ugly to me... is this a decent way to merge queries in rails 3?
scope :active, where("active = ?", true)
scope :not_over_or_in_progress, lambda { where("start_date < ? AND end_date > ? OR end_date IS NULL AND start_date > ? OR end_date IS NOT NULL AND start_date > ?", Date.today, Date.today, Date.today, Date.today) }
scope :valid, not_over_or_in_progress.active.order("start_date DESC")
Try using scopes:
class Event < AR::Base
scope :active, lambda { |date| where("start_date < ? AND end_date > ?", date) }
scope :future, lambda { |date| where("end_date < ?", date }
...
end
# Console
> #active_events = Event.active(Date.today)
> #future_events = Event.future(Date.today)
See http://guides.rubyonrails.org/active_record_querying.html

Resources