Get records created within a certain time period - ruby-on-rails

Hi I'm working on a project, and as part of it I want to be able to get all posts created within the last 7 days. I've tried:
#weeks_posts = Post.where(date: Date.today)
for i in 1..6
#weeks_posts = #weeks_posts + Post.where(date: (Date.today).to_time - i.days)
end
However this ends up returning an array which means I can't chain .where clauses to it, which I need to do, it also seems quite inefficient.
Any help would be greatly appreciated.

You can use scope to make it flexible:
scope :by_dates, ->(start_date, end_date) { Post.where(date: start_date..end_date) }
Post.by_dates(Date.today - 6.days, Date.today) # returns AR collection

Try something like this:
Post.where(date: 1.week.ago.beginning_of_day..Time.now)

Related

Rails - Posts with most comments in last 6 hours ordered by comments count

I can get easily find posts that have been commented on in the last 6 hours. However, I don't know how to order those posts by the number of comments made in the last 6 hours.
This is all I have:
Post.includes(:comments).where(comments: {created_at: 6.hours.ago...Time.now})
How do I order it? If the best way is to use a SQL query, I'm using PostgreSQL if it makes any difference.
I believe you want something like this:
Post.joins(:comments).where('comments.created_at BETWEEN ? AND ?', 6.hours.ago, Time.now).group('posts.id').order('COUNT(comments.id)')
If your requirement is different then feel free to comment and I will try to modify the answer.
I think it would be easiest for you to create a helper method for your Post model which returns the comments count:
def comments_count
comments.count
end
You can now do:
Post.includes(:comments).where(created_at: 6.hours.ago...Time.now).order(:comments_count)
It might be possible to do it without the helper method, I'm not sure but if you wanted to try:
Post.includes(:comments).where(created_at: 6.hours.ago...Time.now).order(:comments.count)

Rails custom model method in where query

In my rails app I have defined in the Kid model a calculation based on the fields from the Kids DB. the method is as follows:
def flip_date
self.dob.advance(months: 10)
end
I want to use this in my controller as I have a method where I am defining something as follows:
new_kids = Kid.where(discharge_date: nil).where('flip_date > ?', Date.current.advance(year: 1).beginning_of_year)
However I keep getting the following error:
SQLite3::SQLException: no such column: flip_date: SELECT "kids".* FROM "kids" WHERE "kids"."discharge_date" IS NULL AND (flip_date < '2017-01-01')
Any ideas on how can I make this work? All help is appreciated!
If you really want to use model methods take a look at http://apidock.com/rails/v4.0.2/ActiveRecord/QueryMethods/select
For your case:
new_kids = Kid.where(discharge_date: nil).select{|k| k.flip_date > Date.current.advance(year: 1).beginning_of_year}
But select method takes every object in memory before returning final result. Hence I will advise to use normal where clause and instead of flip_date take dob (which is a column in database) in consideration.
Like this
new_kids = Kid.where(discharge_date: nil).where('dob > ?', <date criteria>)
The select method (http://apidock.com/rails/v4.0.2/ActiveRecord/QueryMethods/select) works great if you are okay with the return being an Array.
I am still looking for a way to do this with an ActiveRecord_Relation return.
If others know how to do this, it would be much appreciated if you can share.
This example doesn't respond to your specific code, but to the extent it helps someone else with a similar question, here's a very simple example of how .select can be really handy:
#expired_memberships = User.select{|u| u.membership_expired_yesterday?}
In that example you've looped through all your Users and filtered them based on a custom method you defined on the User model (membership_expired_yesterday?). Now you can easily do stuff with that collection like this example in a mailer:
#expirations.each do |user|
MembershipExpirationMailer.with(user: user).first_reminder.deliver_now
end

Rails: Methods in scopes

I have the following method on one of my models:
def remaining_stock
if initial_stock
initial_stock - bought_items
else
0
end
end
In the controller, I'd like to pull all items owned by the user which have a remaining stock greater than zero. So, in short, something like
#remaining_items = Item.where(:user_id => current_user.id).{somehow specify that remaining stock > 0}
The method would be something along the lines of
def has_remaining_stock
remaining_stock > 0
end
But I can't figure out how to add that to either the query itself, or some sort of scope which pulls in has_remaining_stock (I can scope with :conditions, but not other methods)
Any ideas appreciated.
The short answer is that you can't get what you want. Remember, you're generating SQL to be sent off to the database to fetch items. SQL doesn't include Ruby to run per row, but you can do other things with it. Something like:
.where("initial_stock = NULL or (initial_stock - bought_items) > 0")
should work. You could package that up as a scope on your model for cleaner semantics. You just need to express the function in an SQL condition.
I suppose that you can do this is like following:
scope :has_remaining_stock, where("(initial_stock - bought_items) > 0)")

Empty Scope with Ruby on Rails

Following Problem:
I need something like an empty scope. Which means that this scope is emtpy, but responds to all methods a scope usually responds to.
I'm currently using a little dirty hack. I simply supply "1=0" as conditions. I find this realy ugly, since it hits the database. Simply returning an empty array won't work, since the result must respond to the scoped methods.
Is there a better existing solution for this or will I need to code this myself?
Maybe some example code could help explain what i need:
class User < ActiveRecord::Base
named_scope :admins, :conditions => {:admin => true }
named_scope :none_dirty, :conditions => "1=0" # this scope is always empty
def none_broken
[]
end
def self.sum_score # okay, a bit simple, but a method like this should work!
total = 0
self.all.each do |user|
total += user.score
end
return total
end
end
User.admin.sum_score # the score i want to know
User.none_drity.sum_score # works, but hits the db
User.none_broken.sum_score # ...error, since it doesn't respond to sum_score
Rails 4 introduces the none scope.
It is to be used in instances where you have a method which returns a relation, but there is a condition in which you do not want the database to be queried.
If you want a scope to return an unaltered scope use all:
No longer will a call to Model.all execute a query immediately and return an array of records. In Rails 4, calls to Model.all is equivalent to now deprecated Model.scoped. This means that more relations can be chained to Model.all and the result will be lazily evaluated.
User.where('false')
returns an ActiveRecord::Relation with zero elements, that is a chain-able scope that won't hit the database until you actually try to access one of its elements. This is similar to PhilT's solution with ('1=0') but a little more elegant.
Sorry User.scoped is not what you want. As commented this returns everything. Should have paid more attention to the question.
I've seen where('1 = 0') suggested before and Rails should probably cache it as well.
Also, where('1 = 0') won't hit the database until you do .all, .each, or one of the calculations methods.
I thing you need User.scoped({})
How about User.where(id: nil) ?
Or User.where(_id: nil) for mongoid.
The thing you are looking for does not exist. You could implement something like this by monky patching the find method. Yet, this would be an overkill, so I recomend keeping this unless it's performance critical.
Looking at your example code indicates you may not know about aggregated queries in SQL which are exposed as calculations methods in Rails:
User.sum(:score) will give you the sum of all users' scores
Take a look at Rails Guides for more info:
http://guides.rubyonrails.org/active_record_querying.html#sum

Rails - Trying to query from a date range...everything from today [duplicate]

This question already has answers here:
Rails ActiveRecord date between
(11 answers)
Closed 9 years ago.
I'm trying to figure the best way to query a date range from rails...I looked around on Google but am unsure about how to use this syntax.
I have a Model that has various events and I like to add to my find condition a caveat that should only show events where the field :st_date is today or later, in effect only show me data that is current, nothing that happened before today.
I ran into a problem because I have no end date to stop the query, I want to query everything from today to next month.
I was thinking something like
#events = Event.find(:all, :conditions => ["start_date between ? and ?",
date.Today, date.next_month.beginning_of_month])
but I get the error undefined local variable or method `date'......
Do I need do anything particular to use the Date class? Or is there something wrong with my query syntax? I would really appreciate any help.
You want Date.today, not date.today. There's nothing wrong with what you're doing, you're just not referencing the date class properly
Furthermore it would be Date.today.next_month.beginning_of_month
I would take it a step further and define a scope in your model for reuse.
# rails 3 example:
# app/models/event.rb
scope :upcoming, lambda {
where("start_date between ? and ?", Date.today, Date.today.next_month.beginning_of_month)
}
# app/controllers/some_controller.rb
#events = Event.upcoming
There is also a great Railscasts episode on scopes in Rails 3:
http://railscasts.com/episodes/202-active-record-queries-in-rails-3
Event.where(:start_date => Date.today..Date.today.next_month.beginning_of_month) also works great.
Take a look at my by_star plugin which lets you do things like:
Event.by_month(Time.now, :field => "start_date")

Resources