How can I show closest date-to-happen posts? - ruby-on-rails

I am building a site that displays a weekly resume of what will be going on.
My problem is: an admin can place a post two months from now, how can I restrict those posts from showing up until the week it would actually happen?

Use a scope or two:
class Post < ActiveRecord::Base
scope :future, lambda { where('ends_at > ?', Time.zone.now') }
scope :up_to, lambda { |time| where('starts_at < ?', time) }
end
#coming_up_posts = Post.future.up_to(7.days.from_now)

Related

Track daily users signin

So I want to output users that signed in 2 hours ago with the hope I will call it on the front end, and I have a database attribute (created_at)that keeps track of the time you sign in.
What I did was to define a scope to handle that which got nothing from. Here is my code below:
class SignupHistory < ActiveRecord::Base
scope :one_hour_ago, -> { where 'created_at > ?', Time.now - 2.hours.ago }
end
How do I go about showing users that logged in 2 hours ago?
Am I correct to understand that you are trying to find all the records that were created within the last two hours? Then, you can just test against 2.hours.ago without any subtraction operator:
scope :two_hours_ago, -> { where 'created_at > ?', 2.hours.ago }
I think your problem is that you're calling .ago.
You should be able to accomplish what you need by calling:
scope :one_hour_ago, -> { where 'created_at > ?', Time.zone.now - 2.hours }

ActiveRecord: Get all users who should be banned today

I have two models:
class User < ActiveRecord::Base
has_many :ban_messages, dependent: :destroy
end
class BanMessage < ActiveRecord::Base
belongs_to :user
end
Table BanMessage contains a field t.datetime :ban_date that stores the date, when user should be banned. User table contains a field status, that contains one of the status values (active, suspended, banned). When I send BanMessage to User, his status field changes from 'active' to 'suspended'. Also I can activate user back, so he would not be banned at ':ban_date', but his BanMessage wouldn't be destroyed.
So I need to create query for selecting all Users with status 'suspended', who have in their newest BanMessages records 'ban_date' field, with DateTime value, which is between 'DateTime.now.beginning_of_day' and 'DateTime.now.end_of_day'.
You can filter your users with where query followed by join method for associated ban_messages with where method to further filter with the date range.
User.where(status: 'suspended').joins(:ban_messages).where("ban_date >= ? AND ban_date <= ?", DateTime.now.beginning_of_day, DateTime.now.end_of_day )
Try something like this.
User.joins(:ban_messages).where(status: :suspended).where('ban_messages.ban_date BETWEEN :begin_time AND :end_date', begin_time: DateTime.now.beginning_of_day, end_time: DateTime.now.end_of_day)
Here's what I needed:
User.joins(:ban_messages)
.where('users.status = ?', :suspended)
.where('ban_messages.created_at = (SELECT MAX(ban_messages.created_at) FROM ban_messages WHERE ban_messages.user_id = users.id)')
.where('ban_messages.ban_date BETWEEN ? and ?', DateTime.now.beginning_of_day, DateTime.now.end_of_day)
.group('users.id')
UPDATE
MrYoshiji: The caveat in your code is that if you miss one day, then
the next day you won't see the people that should have been banned the
day before. You might want to get all User where the ban_date is
lesser than DateTime.now.end_of_day, either in the same view or
another one.
So final query might be something like this
User.joins(:ban_messages)
.where('users.status = ?', :suspended)
.where('ban_messages.created_at = (SELECT MAX(ban_messages.created_at) FROM ban_messages WHERE ban_messages.user_id = users.id)')
.where('ban_messages.ban_date < ?', DateTime.now.end_of_day)
.group('users.id')

Rails scope filter by date range

There are many questions relate to rails date range problem but mine is a little more complicated.
I have two models: house and booking. A House has_many bookings. A Booking has two attributes in date format: check_in and check_out.
What I want to achieve: Giving a valid date range, show all houses that are available during this range. In detail:
The start date of the range should not be in any booking.
The end date of the range should not be in any booking.
There should not be any booking between the start and the end.
Can this be done using the rails scope?
UPDATE:
I found the code below that can check scope date interval that overlaps.
named_scope :overlapping, lambda { |interval| {
:conditions => ["id <> ? AND (DATEDIFF(start_date, ?) * DATEDIFF(?, end_date)) >= 0", interval.id, interval.end_date, interval.start_date]
}}
How can I transfer this to my problem?
scope :overlapping, (lambda do |start_date, end_date|
House.includes(:bookings).where("bookings.check_in < ? AND bookings.check_out > ?",
start_date, end_date).references(:bookings).uniq
end)
I went ahead and deleted the >= and <= operators in favor of > and < to explicitly show these bookings being outside of the given range, but you can adjust them per your needs!
Update
Changed query to use #includes instead of #joins, since we're querying the attached table.
Yes it is possible to have this query through scope. Put this scope in house model.
scope :overlapping, -> (start_date, end_date) {
includes(:bookings).where('bookings.check_in < ? AND bookings.check_out > ?',
start_date.to_date, end_date.to_date)
}
And call as House.overlapping('2015-07-01', '2015-07-09')

How to get records created at the current month?

I have a candidate which has_many votes.
I am trying to get the votes of a candidate that were created in the current month?
#candidate.votes.from_this_month
scope :from_this_month, where("created_at > ? AND created_at < ?", Time.now.beginning_of_month, Time.now.end_of_month)
That gives me a PG error:
PG::Error: ERROR: column reference \"created_at\" is ambiguous
If I try
scope :from_this_month, where("vote.created_at > ? AND vote.created_at < ?", Time.now.beginning_of_month, Time.now.end_of_month)
I get the following error
PG::Error: ERROR: missing FROM-clause entry for table "vote"
Correct scope
scope :from_this_month, lambda {where("votes.created_at > ? AND votes.created_at < ?", Time.now.beginning_of_month, Time.now.end_of_month)}
This is because in rails the model names are singular(i.e Vote) and tables created are pural (e.g. votes) by convection
EDIT
This can be written simpler with lambda {where(created_at: Time.now.beginning_of_month..(Time.now.end_of_month))} and we need to use lambda due to the reason given in below comments.
Thanx BroiSatse for reminding :D
You need to enclose the where in a lamda as well.
scope :from_this_month, lambda { where("votes.created_at > ? AND votes.created_at < ?", Time.now.beginning_of_month, Time.now.end_of_month) }
Otherwise it may appear to work and your tests will all pass, but if your app runs for more than a month you will start to get incorrect results because Time.now is evaluated when the class loads, not when the method is called.
From Rails 5 you have a much cleaner syntax. On your votes model add a scope this_month
scope :this_month, -> { where(created_at: Date.today.all_month) }
You can now query #candidates.votes.this_month
scope :this_month, -> { where(created_at: Time.zone.now.beginning_of_month..Time.zone.now.end_of_month) }
and you can call the scope:
Model.this_month
You could use an ActiveRecord Association Extension:
#app/models/Candidate.rb
Class Candidate < ActiveRecord::Base
has_many :votes do
def from_this_month
where("created_at > ? AND created_at < ?", Time.now.beginning_of_month, Time.now.end_of_month)
end
end
end
This should allow you to call #candidate.votes.from_this_month to return the required conditional data

association data in rails model scope

I have a model named Post (blog post) and a model named Category. Each post belongs_to a category. Each category has an attribute named retainer that specifies the amount of time before a post "expires", so for example movies_category.retainer = 30.days
What I'm trying to do is create a scope for Post that finds all of the posts which are "expired". So for example, assuming I were to hardcode the value of 30.days and it were to apply to all categories (therefore all posts), the scope would be:
scope :expired, lambda { where("posts.created_at < ?", 30.days.ago) }
However, instead of hardcoding the value 30.days.ago, I want to get the retainer value from the post's category and base the condition on that, so something like:
scope :expired, lambda { where("posts.created_at < ?",
Time.now - post.category.retainer) }
So put into words: I want to get all of the posts which are expired, and the expiration status is determined by each post's category's retainer value (i.e. posts in the movies category expire in 10 days, posts in the games category expire in 5 days, etc.)
Is this even possible? Would I require some form of join or something?
scope :expired, lambda { |retainer| where("posts.created_at < ?",
Time.now - retainer) }
Then just use it like:
Post.expired(post.category.retainer)
Or from the category model like:
def Posts
Post.expired(retainer)
end

Resources