Scope to get users older then 18 years old by birthday field (Rails 3.2) - ruby-on-rails-3

I need to write scope that will help me get users where age will be > 18 years, but I don't have age field in database.
My solutions doesn't works =(
1. scope :adult, -> { where('Time.now.utc.to_date.year - birthday.to_date.year >= 18') }
2. scope :adults, -> { where('birthday >= ?', age) }
def age
Date.today - 18.years
end

try this
scope :adults, -> { where('birthday <= ?', 18.years.from_now) }

Related

is there any way that can offset from specific record when using scope

i have a lot of methods that look for records after specific active record. examples are:
def photo_recent
offsetphoto = Photo.find(params[:id])
#photos = Photo.recent.where('created_at> ?', offsetphoto.id).limit(10)#recent is a scope using created_at
end
def photo_recent
offsetphoto = Photo.find(params[:id])
#photos = Photo.popular.where('like_count > ?', offsetphoto.like_count).limit(10)#popular is a scope using like_count
end
i was wondering if there is any way to modularize this such as:
#photos = Photo.recent.offset(Photo.find(params[:id])).limit(10)
# models/photo.rb
scope :most_recent_starting_from, -> (photo) { order(created_at: :asc).where('created_at >= ?', photo.created_at) }
Example Usage
photo = Photo.find(123)
ten_next_created_photos_after_photo = Photo.most_recent_starting_from(photo).limit(10)
You could write a scope that just takes everything from the current Photo
scope :offset_from, -> (photo) { where('id >= ?', photo.id) }
Photo.offset_from(Photo.find(params[:id]))......

Rails: Two 'where' queries - each works individually, but not together

I want to write something like:
#meeting_requests = Meeting.where('meeting_time >= ? AND requestee_id IS ?
AND status = ?', Date.today, nil, "Active")
.joins(:requestor)
.where('birthyear >= ? AND birthyear <= ?',
current_user.birthyear - 10,
current_user.birthyear + 10 )
This works:
#meeting_requests = Meeting.where('meeting_time >= ? AND requestee_id IS ?
AND status = ?', Date.today, nil, "Active")
And this works:
#meeting_requests = Meeting.joins(:requestor)
.where('birthyear >= ? AND birthyear <= ?',
current_user.birthyear - 10,
current_user.birthyear + 10 )
And something like this works:
Meeting.joins(:requestor).where('birthyear > ?', 1900).where(status: "Active")
but I need to do a greater than query on the meeting_time, so I need to write it as a string I think?
But together both sql queries produce an error of: ambiguous column name: status: SELECT
I feel like I'm so close... what am I missing here?
This is a message that appears when it is not clear which table the column comes from. This should work:
...rest_of_statement.where('meetings.status' => 'Active')

Compare Time.now in Rails but ignore year?

I have the following code in my Rails 3 application:
scope :active, lambda {
where("starts_at <= ? AND ends_at >= ?", Time.now.utc, Time.now.utc)
}
scope :since, lambda { |hide_time|
where("updated_at > ? OR starts_at > ?", hide_time.utc, hide_time.utc) if hide_time
}
def self.display(hide_time)
active.since(hide_time)
end
However, I want to return the results regardless of whether the year matches the current year or not. So long as the day and month match it's fine. Is this possible?
The starts_at and ends_at columns are datetime formatted. So they will automatically include a year even if I dont set one in the form:
<%= f.datetime_select :starts_at, :order => [:day, :month], :discard_year => true %>
Any pointers would be appreciated.
As Old Pro points out in the comments this does pose a problem with leap years. You likely want to split each dayofyear into MONTH(x) AND DAYOFMONTH(x) instead.
You can use the dayofyear function
https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_dayofyear
scope :active, lambda {
where("dayofyear(starts_at) <= dayofyear(?) AND
dayofyear(ends_at) >= dayofyear(?)", Time.now.utc, Time.now.utc)
}
scope :since, lambda { |hide_time|
where("dayofyear(updated_at) > dayofyear(?) OR
dayofyear(starts_at) > dayofyear(?)", hide_time.utc, hide_time.utc) if hide_time
}
in mssql it's
datepart(dayofyear,date)
in postgres it's
extract(DOY from date)
in sqlite3 it's
strftime("%j",date)

ActiveRecord Subquery Comparison as a Scope

I'm rewriting a manual SQL query into an ActiveRecord query for use in a Rails app.
What it does it collect two groups of users from the same table: 1 who have a qualifying event (44 or 48) in the last week, and a group of users who have the same qualifying event a month ago.
This is the current query. I'm not sure how to turn this into an ActiveRecord scope:
select top 500 active_users_last_week.email
from (
select distinct(email) from user_event_tracking
where event_id in (44,48)
and sitedb_created_date between getdate()-8 and getdate()-1
and sitedb_name = 'XYZ'
and email not like '%#company.com'
and email not like '%#other_company.com'
) active_users_last_week,
(
select distinct(email) from user_event_tracking
where event_id in (44,48)
and sitedb_created_date between getdate()-60 and getdate()-30
and sitedb_name = 'XYZ'
and email not like '%#company.com'
and email not like '%#other_company.com
) active_users_last_month
where active_users_last_week.email = active_users_last_month.email;
Any suggestions on how to turn this into an ActiveRecord scope? I have these set as scopes already:
scope :active_events, lambda {
where("event_id in (44,48)")
}
scope :for_property, lambda { |property|
where('sitedb_name = ?', property)
}
scope :last_week, lambda {
where("sitedb_created_date between GETDATE()-8 and GETDATE()-1")
}
scope :last_month, lambda {
where("sitedb_created_date between GETDATE()-60 and GETDATE()-30")
}
scope :no_test_users, lambda {
where("email not like '%#company.com' and email not like '%#other_company.com'")
}
The scopes all work individually (and with each other). The question is how to get emails that are in both Event.active_events.last_week and Event.active_events.last_month in an efficient way.
Try this:
Event.select(:email).where(:event_id => [44,48], sitedb_created_date => (8.days.ago..1.day.ago), :sitedb_name => 'XYZ', :email => Event.select(:email).where(:event_id => [44,48], sitedb_created_date => (60.days.ago..30.days.ago), :sitedb_name => 'XYZ').where(Event.arel_table[:email].does_not_match_all(["%company.com","%other_company.com"])))
You might need to tinker with days to adjust them to your date range, I am not 100% sure if they are inclusive or not. You might need to change 8.days.ago to 7.days.ago etc.
You also should be able to do this with your scopes:
Event.active_events.last_week.where(:email => Event.active_events.last_month.select(:email))

Rails 3 Time.now without the year?

I have a Rails 3 application that is a basic intranet for our company. I have an announcement controller which checks for any announcements that have been created with a scheduled date that matches the current date.
class Announcement < ActiveRecord::Base
scope :active, lambda {
where("starts_at <= ? AND ends_at >= ?", Time.now.utc, Time.now.utc)
}
scope :since, lambda { |hide_time|
where("updated_at > ? OR starts_at > ?", hide_time.utc, hide_time.utc) if hide_time
}
def self.display(hide_time)
active.since(hide_time)
end
end
However, most announcement will be deleted within a week or so of the scheduled end date. All other announcements are simple Happy Birthday messages to staff members. Due to the way we are using the announcement system, it seems sensible to only check against the day/month and not the year, as birthday messages etc. will be annual.
What would the simplest way to 'ignore' the year in my controller code?
UPDATE
I have updated the controller code to the below code, however, announcements no longer hide after the end datetime.
class Announcement < ActiveRecord::Base
scope :active, lambda {
where("day(starts_at) <= ?
AND month(starts_at) <= ?
AND day(ends_at) >= ?
AND month(ends_at) >= ?",
Time.now.utc.day,
Time.now.utc.month,
Time.now.utc.day,
Time.now.utc.month)
}
scope :since, lambda { |hide_time|
where("day(starts_at) > ?
AND month(starts_at) > ?",
hide_time.utc.day, hide_time.utc.month) if hide_time
}
def self.display(hide_time)
active.since(hide_time)
end
end
An example record:
22, 'Test Announcement', 'This is a test announcement, please ignore it. Seriously - stop reading.', '2012-06-25 13:40:00', '2012-06-25 13:55:00', '2012-06-25 13:47:23', '2012-06-25 13:52:15');
Even though I have set :exclude_year on the input select boxes for the datetime fields it still puts the current year in.
If you are using MySQL database you could use its day() and month() methods. I don't know if these methods can be found for other databases as well. So doing it this way may make your code become dependent on the database server.
scope :active, lambda {
where("day(starts_at) <= ?
AND month(starts_at) <= ?
AND day(ends_at) >= ?
AND month(ends_at) >= ?",
Time.now.utc.day,
Time.now.utc.month,
Time.now.utc.day,
Time.now.utc.month)
}
Couple things. You should be using AND not OR if I understand you correctly, you want the time to fall between those to items. 2nd thing is you need to specify that it is at the beginning of the day and the end of the day. Right now it's just being set to the now which doesn't really say the expanse of 24 hours very clearly :
class Announcement < ActiveRecord::Base
scope :active, lambda {
where('starts_at < ? AND ends_at > ?', Time.zone.now.end_of_day, Time.zone.now.beginning_of_day)
}
scope :since, lambda { |hide_time|
where('updated_at > ? AND starts_at > ?', Time.zone.now.end_of_day, Time.zone.now.beginning_of_day)
}