Validation date in specific range - ruby-on-rails

Hi I have model bought_details and entry_types.
# Table name: bought_details
#
# id :integer not null, primary key
# bought_data :date not null
# end_on :date not null
# entry_type_id :integer
# person_id :integer
# start_on :date
# cost :decimal(5, 2) not null
# Table name: entry_types
#
# id :integer not null, primary key
# kind :string not null
# kind_details :string not null
# description :text
# price :decimal(5, 2) not null
What I want to have:
If I register new purchase e.g. person with id 1 buy pass(entry_type id: 1) for 1 month(start_on: 20.04.2016 end_on: 20.05.2016).
I want create validation to protect buy new pass(entry_type kind == "Pass", in a database I have few entry type object with kind equals "Pass"), when start_on or end_on is between 20.04.2016 and 20.05.2016r. with simply alert "You already have valid pass".
How can I resolve my problem?
Thanks in advance.

Have you try validates_timeliness gem?
https://github.com/adzap/validates_timeliness
It can simply validate date ranges.
validates_date :start_on, after: lambda { (DateTime.now - 1.month }, before: lambda { (DateTime.now + 1.month }

Related

Multiple group queries using sum & count

So for the given model
# == Schema Information
#
# Table name: faction_armories
#
# id :bigint not null, primary key
# action :string
# qty :integer
# tid :string
# timestamp :datetime
# user_name :string
# created_at :datetime not null
# updated_at :datetime not null
# faction_id :integer
# item_id :integer
# user_id :integer
#
I'm attempting to group user_name, action, and item_id, and add up all the qty's from each entry. For example
action="used","user_name"="me","qty"=5,"item_id"=4
action="used","user_name"="me","qty"=10,"item_id"=4
Should return a hash that identifies that me - used item 4 - 15 times.
Currently, I'm running two queries but still, the data is not coming through correctly, any input would be greatly appreciated
#news = FactionArmory.where(faction_id: current_user.faction_id).order(user_name: :asc).where("timestamp >= ?", params["report_start"]).where("timestamp <= ?", params["report_end"]).includes([:item]).group("user_name", "action", "item_id").count
#qty = FactionArmory.where(faction_id: current_user.faction_id).order(user_name: :asc).where("timestamp >= ?", params["report_start"]).where("timestamp <= ?", params["report_end"]).includes([:item]).group("user_name", "action", "item_id").sum(:qty)
You can select or pluck to get multiple calculations in one query
FactionArmory
.group("user_name", "action", "item_id")
.pluck("user_name", "action", "item_id", "count(distinct faction_armories.id) as count", "sum(qty) as qty_sum")

Getting most liked news from the query

There are two models:
# == Schema Information
#
# Table name: news
#
# id :integer not null, primary key
# title :string not null
# content :text not null
# scope :string not null
# created_at :datetime not null
# updated_at :datetime not null
# person_id :integer not null
# == Schema Information
#
# Table name: likes
#
# id :integer not null, primary key
# like :boolean
# person_id :integer not null
# news_id :integer not null
Relation
news has many likes
like belongs to news
I want to get most liked news from query. Query should substract count of likes equal true from likes equal false. The highest number is most liked news.
What I tried:
#count_true_likes = Like.where('likes.like = ?', true).group(:news_id).count
#count_false_likes = Like.where('likes.like = ?', false).group(:news_id).count
Result is Hash with id and counted likes. I don't have idea how to subtract in query positive likes from negative likes, and do it for every news.
This kind of querying becomes prohibitively slow very quickly, as your dataset grows. A common workaround is to cache number of upvotes and downvotes. For example
# Table name: news
#
# id :integer not null, primary key
# title :string not null
# content :text not null
# scope :string not null
# created_at :datetime not null
# updated_at :datetime not null
# person_id :integer not null
#
# upvotes_count :integer not null
# downvotes_count :integer not null
# vote_result :integer not null
Where vote_result is a cached upvotes_count - downvotes_count.
Then simply do
News.order(vote_result: :desc).limit(10) # top 10 articles
The downside is, of course, that you need to maintain those cached counters (increase/decrease corresponding ones when you register a vote).
I resolved my problem:
#most_liked_news_id = Like.group(:news_id)
.select('news_id, SUM(case when likes.like then 1 else -1 end) as max_positive')
.order('max_positive desc').map(&:news_id).first
#most_liked_news = News.find(#most_liked_news_id)

Rails filter on date returning no results

I'm trying to filter records that were assigned on particular day (today) using this query:
assignments = p.assignments.where("assigned_date = ?", Date.today)
Even though I know these records exist, I always get a blank result back.
I've also tried ...where(:assigned_date => Date.today) with no luck.
The database schema is:
# == Schema Information
#
# Table name: assignments
#
# id :integer not null, primary key
# name :string(255)
# rep :integer
# set :integer
# instructions :text
# created_at :datetime not null
# updated_at :datetime not null
# player_id :integer
# actual_percentage :float
# predicted_percentage :float
# assigned_date :date
#
And in the console, when I type
p.assignments.first.assigned_date == Date.today
it returns true.
Any idea what I'm doing wrong?
DateTime holds a date and a time, so you're looking for records that have a precise value, not just the same day.
assignments = p.assignments.where('assigned_date BETWEEN ? AND ?', DateTime.now.beginning_of_day, DateTime.now.end_of_day).all
should return what's expected
P.S.
all credits to Tadman

How do I compare two rows of two different tables in Rails 3.2.8

I need to compare a row of 7 attributes in a winning_numbers table with 1 or more rows in another table, lottery_selections, containing 6 attributes in rails 3.2.8. From the result I want to count the number of attributes from one table that match the other and render the result.
I have two models: lottery_selections & winning_numbers
# == Schema Information
#
# Table name: lottery_selections
#
# id :integer not null, primary key
# syndicate_id :integer
# lottery_selection_1 :integer
# lottery_selection_2 :integer
# lottery_selection_3 :integer
# lottery_selection_4 :integer
# lottery_selection_5 :integer
# lottery_selection_6 :integer
# lottery_selection_date :datetime
# created_at :datetime not null
# updated_at :datetime not null
#
class LotterySelection < ActiveRecord::Base
attr_accessible :lottery_selection_1, :lottery_selection_2, :lottery_selection_3, :lottery_selection_4,\
:lottery_selection_5, :lottery_selection_6, :lottery_selection_date, :syndicate_id
belongs_to :winning_number
#validates_associated :winning_number
validates :lottery_selection_1, :lottery_selection_2, :lottery_selection_3, :lottery_selection_4,\
:lottery_selection_5, :lottery_selection_6, :presence => true, :numericality => {:greater_than_or_equal_to => 1}, \
:numericality => {:less_than_or_equal_to => 49}
UNIQU_FIELDS = [:lottery_selection_1, :lottery_selection_2, :lottery_selection_3, :lottery_selection_4,\
:lottery_selection_5, :lottery_selection_6]
validate :lottery_numbers_are_unique
def lottery_numbers_are_unique
unless UNIQU_FIELDS.map{|field| self[field] }.uniq.length == UNIQU_FIELDS.length
errors[:base] << "You have repeated one or more numbers for that day's draw"
end
end
end
# == Schema Information
#
# Table name: winning_numbers
#
# id :integer not null, primary key
# winning_numbers_date :datetime
# winning_number_1 :integer
# winning_number_2 :integer
# winning_number_3 :integer
# winning_number_4 :integer
# winning_number_5 :integer
# winning_number_6 :integer
# winning_number_bonus :integer
# created_at :datetime not null
# updated_at :datetime not null
#
class WinningNumber < ActiveRecord::Base
attr_accessible :winning_number_1, :winning_number_2, :winning_number_3, :winning_number_4, :winning_number_5,\
:winning_number_6, :winning_number_bonus, :winning_numbers_date
has_many :lottery_selections
#validates_associated :lottery_selections
validates :winning_number_1, :winning_number_2, :winning_number_3, :winning_number_4, :winning_number_5,\
:winning_number_6, :winning_number_bonus, :presence => true, :numericality => {:greater_than_or_equal_to => 1}, \
:numericality => {:less_than_or_equal_to => 49}
#Below checks that for any given date there can only be one set of winning numbers
validates :winning_numbers_date, uniqueness: { scope: [:winning_number_1, :winning_number_2, :winning_number_3,\
:winning_number_4, :winning_number_5, :winning_number_6, :winning_number_bonus] }
UNIQ_FIELDS = [:winning_number_1, :winning_number_2, :winning_number_3, :winning_number_4, :winning_number_5, :winning_number_6, :winning_number_bonus]
validate :winning_numbers_are_unique
def winning_numbers_are_unique
unless UNIQ_FIELDS.map{|field| self[field] }.uniq.length == UNIQ_FIELDS.length
errors[:base] << "You have repeated one or more numbers for that day's draw"
end
end
end
Can you please advise on how I make the comparison and use the result to render a result?
Most effective solution (even more rails developer will advise not to do it): Create a stored procedure on the database where you can do the comparison and return the result.
Something quick you can do (although the more you research the better, on a lottery app you may have a lot of tickets and you need to run something that is really effective):
winning_numbers = # Do a query and put the array of winning numbers here
seven_numbers_match = LotterySelection.where("number_1 in (?) and number_2 in (?) and number_3 in (?) and number_4 in (?) and number_5 in (?) and number_6 in (?) and number_7 in (?)", winning_numbers, winning_numbers, winning_numbers, winning_numbers, winning_numbers, winning_numbers, winning_numbers)
six_number_match = LotterySelection.where("(number_1 in (?) and number_2 in (?) and number_3 in (?) and number_4 in (?) and number_5 in (?) and number_6 in (?) and number_7 not in(?)") OR (number_1 in (?) and number_2 in (?) and number_3 in (?) and number_4 in (?) and number_5 in (?) and number_6 not in (?) and number_7 in (?)) OR (...")
And so on, it may not be the best algorithm but it works and use the db engine to do the compassion.
But definitely for a problem like this, I'll simply hire a DBA consultant to write the stored procedure for me.

Dealing with time periods in Rails 3.1

I'm developing a booking system in Rails 3.1. I have created a model for a Booking:
# == Schema Information
#
# Table name: bookings
#
# id :integer not null, primary key
# product_id :integer
# customer_id :integer
# booked_from :datetime
# booked_to :datetime
# paid :boolean
# payment_type :string(255)
# created_at :datetime
# updated_at :datetime
#
So what I want to do is to validate each entry and check whether the desired time period (booked_from - booked_to) is overlapping any period of another booking with the same product_id. The products also have an available_from and available_to field which it also has to validate against.
How do I do this?
Check if this works:
class Booking
validate :booking_period_not_overlapped
private
def booking_period_not_overlapped
unless Booking.where(
'(booked_from <= ? AND booked_to >= ?) OR (booked_from >= ? AND booked_from <= ?)',
booked_from, booked_from,
booked_from, booked_to
).empty?
errors.add(:booked_from, 'Invalid period.')
end
end
end
It just checks if there is any existing records whose booked_from and booked_to satisfy one of the following conditions (suppose your new booking is from 16:00 to 17:00):
it starts before the new booking, and not yet ended (e.g. 15:00 - 16:30 or 15:00 - 17:30)
it starts within the new booking period (e.g. 16:20 - 16:50 or 16:30 - 17:30)

Resources