I want to create a scope, I want to get all Orders in which has passed more than 24hrs since the last time they were updated.
I want to get all those Orders for then loop in them:
Order.more_than_24_updated.find_each do |order|
#do some stuff with each order
end
I do not know how to add 24hrs to the updated_at attribute of orders in the scope:
scope :more_than_24_updated, -> { where(status: "pago_pendiente").where('#{Time.now} >= ?', updated_at + 24.hours) }
Well I know the above does not work, but well... how to do this?
You can try something like this:
scope :more_than_24_updated, -> {where('status = ? and updated_at <= ?', :pago_pendiente, 24.hours.ago)}
You can try this one
scope :more_than_24_updated, -> { where(status: "pago_pendiente").where("NOW() - '24 hours'::INTERVAL >= updated_at") }
Related
I have parent model Project & children model ToDo.
A project has many ToDos with column starts_at & ends_at.
I would like to search for projects that have 'any' todos in the time range.
Here I wrote some codes, however, it is not as expected.
class Project
has_many :todos
scope :active, -> {joins(:todos).where("todos.starts_at < '#{Time.now}' AND todos.ends_at > '#{Time.now}'").distinct}
scope :waiting, -> {joins(:todos).where.not("todos.starts_at < '#{Time.now}' AND todos.ends_at > '#{Time.now}'").distinct}
scope :done, -> {where("project_due > ?", Time.now)}
end
Active one seems right, but waiting scope also contains the projects that have more than one todos.
I wonder if there any solution to compare starts_at & ends_at per each todo. Not like above.
Thanks ahead.
*# Update *
This is what I wanna achieve. but in one query.
scope :waiting, -> { joins(:todos).where.not(id: active.ids).where('finishing > ?', Time.now).distinct }
Try to the following
Update
For waiting you mean starts_at greater than NOW right? then it will be
scope :waiting, -> {joins(:todos).where("todos.starts_at >= ?", Time.now).distinct}
If the match with the first condition then you don't need to match the second condition, you can write with the second condition like this
scope :waiting, -> {joins(:todos).where("todos.starts_at > '#{Time.now}' AND todos.ends_at > '#{Time.now}'").distinct}
but don't need.
Update 2
Remove the not from where, here not means active
scope :waiting, -> {joins(:todos).where("todos.starts_at >= ?", Time.now).distinct}
Update 3 after Update 2 worked
scope :waiting, -> {joins(:todos).where("todos.starts_at >= ?", Time.now).distinct}
scope :finished, -> {where("finishing > ?", Time.now).distinct}
scope :waiting_n_progress, -> {where.not(id: active.ids).finished.waiting}
the waiting_n_progress scope, I think you will get your goal, remember that's not tested.
Hope it should work.
Your query for waiting basically translate from !(start < now && end > now) to this start >= now || end <= now which would most likely return a lot more projects than you wanted. See if that is the logic that you wanted.
Also, for best Rails practices, you should write query like the user fool-dev suggested in the other answer using question mark. This is to prevent SQL injection as explained in more details here
EDIT
So I think you mean waiting means projects that does not have any Todo or those that have awaiting Todo (start_at > now). I think this should work:
scope(:waiting) { includes(:todos).where('todos.project_id IS NULL OR todos.start_at > ?', Time.now).distinct }
The first part is to select projects that doesn't have any Todo and the second part is self explanatory.
I want to get all records of matching wiht query, I get multiple params and save them in query like that
query = Hash.new
query[:user_id] = params["user_id"] if query["user_id"]
query[:vehicle] = params["vehicle_id"] if query["vehicle_id"]
trips = Trip.where(query)
I also want to add params['created_at] if these params are present but no idea how to do it
You could add a scope to your Trip model.
scope :created_after, ->(time) { where("created_at > ?", time) if time }
Then chain it like so:
Trip.created_after(params["created_at"]).where(query)
Not the most elegant, but it will work. If "created_at" is not in the params, it will be nil and will just return all trips.
Just for fun and riffing off the answer provided by Paul Byrne and this Q&A, perhaps something like:
params.slice(:user_id, :vehicle_id).compact.
each_with_object(Trip.created_after(params[:created_at])) do |(key, value), scope|
scope.merge(Trip.send(key, value))
end
I have this scope to show recent posts, but I want outdated sticky posts to be shown as well. That is, the sticky post is created 3 days ago and the first condition is picked that post out, however, I also need the post which has a "sticky: true" boolean value to be included in the :to_show scope.
I tried this, but not working.
scope :to_show, -> { where("created_at > ?", Time.now - 1.day).except(sticky: true).order("created_at desc") }
Please advise.
It sounds like you're trying to do the following:
Include all posts that are 'sticky'
Include all posts that have been created in the last day
Order those posts from newest to oldest (do you want sticky posts to be ordered first?)
In that case what you really want is an 'or' condition in your where clause. Something like
scope :to_show, -> { where("(sticky = 1) OR (created_at > ?)", Time.now - 1.day).order("created_at desc") }
If you want to put the sticky items at the top, then the order clause would change to
scope :to_show, -> { where("(sticky = 1) OR (created_at > ?)", Time.now - 1.day).order("sticky desc, created_at desc") }
I have the following scope:
scope :this_month, :conditions => ["created_at >= ?", Date.today.beginning_of_month]
Which makes the SQL output of a.response_sets.this_month.to_sql:
SELECT "response_sets".* FROM "response_sets" WHERE created_at >= '2012-05-01'
But since today is actually June 1, that date seems wrong. So, I tried bypassing the scope and just doing a condition directly, like so:
a.response_sets.where(["created_at >= ?", Date.today.beginning_of_month]).to_sql
Which then, outputs:
SELECT "response_sets".* FROM "response_sets" WHERE created_at >= '2012-06-01'
Which is correct. So why is there a difference between doing Date.today.beginning_of_month in a scope and doing it directly in where?
When working with dates in scopes you should use a lambda so the scope gets evaluated every time it is called:
scope :this_month, -> { where("created_at >= ?", Date.today.beginning_of_month) }
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