Grouping in Rails 4 - ruby-on-rails

I have a calendar and I want to group this data..so I have this in my controller
#entry_by_date = Entry.where("emp_mail_addr = ? and emp_first_name = ? and emp_last_name = ? and emp_dept = ?", current_user.email, current_user.emp_first_name, current_user.emp_last_name, current_user.emp_dept).group_by {|i| i.leave_start.to_date}
#date = params[:date] ? Date.parse(params[:date]) : Date.today
Question is for #entry_by_date I have it .group_by {|i| i.leave_start.to_date}
how can I make this have group by two dates for example....
#entry_by_date........group_by {|i| i.leave_start.to_date} {|i| i.leave_end.to_date}
So it will now group by leave_start and leave_end so now on my calendar it will show up with leave start and leave end dates..
I tried doing it like this
#entry_by_date = Entry.where("emp_mail_addr = ? and emp_first_name = ? and emp_last_name = ? and emp_dept = ?", current_user.email, current_user.emp_first_name, current_user.emp_last_name, current_user.emp_dept).group_by {|i| i.leave_start.to_date}
#entry_by_date = Entry.where("emp_mail_addr = ? and emp_first_name = ? and emp_last_name = ? and emp_dept = ?", current_user.email, current_user.emp_first_name, current_user.emp_last_name, current_user.emp_dept).group_by {|i| i.leave_end.to_date}
but only leave start showed up or if I switched them leave end would show up. I would like for both to show up and suggestions are greatly appreciated!!!!
Thank you!

Be aware that there is a critical difference between group_by and group APIs - the former works on lists (after they have been fetched from the database), while the latter is used in the database query itself (adding it a GROUP BY clause)
I'm not sure what you are trying to achieve, but if you want to have the keys of your group to be an array of dates, you could do it in a single group_by block:
#entry_by_date = entries.group_by { |i| [i.leave_start.to_date, i.leave_end.to_date] }
If you want each entry to be grouped twice (once with its start date, and once with its end date), you need to create 2 grouped maps, and join them:
entry_by_start_date = entries.group_by {|i| i.leave_start.to_date}
entry_by_end_date = entries.group_by {|i| i.leave_end.to_date}
#entry_by_date = entry_by_start_date.merge(entry_by_end_date) {|key, oldval, newval| newval + oldval}

Related

Ruby on Rails iterate array result into query

Following were my output from the query:
unless #slug == 'all'
#city = '' if #city.blank?
#city = #city.gsub("-", " ")
country = Country.where("lower(name) LIKE ?", "#{#city.downcase}")
gon.country = country
if country.present?
end
if #city.present?
#products = #products.where("lower(city) LIKE ? or lower(country) like ? or lower(state) LIKE ?", "%#{#city.downcase}%", "%#{#city.downcase}%","%#{#city.downcase}%")
#city_obj = City.where("lower(name) LIKE ?", "%#{#city.downcase}%").first
end
end
Here gon.country return result as:
Object
countries
:
Array[2]
0
:
"california"
1
:
"san francisco"
How can I iterate the countries and pass it to get #products result?
You can do it in two ways :
Iterate all country record and then add like query.
#product = []
country.each do |con|
#products << #products.where("lower(city) LIKE ? or lower(country) like ? or lower(state) LIKE ?", "%#{con.downcase}%", "%#{con.downcase}%","%#{con.downcase}%")
end
You can use ILIKE syntax of core sql. Which work like this :
select * from table where value ilike any (array['%foo%', '%bar%', '%baz%']);
# in your case
country_array_with_percent = country.map {|con| "%#{con}%" }
#products.where("name ILIKE ANY ( array[?] )", country_array_with_percent)
You can also make query chaining with or query, More details here

rails conditions based on attributes presence

I was wondering if there's a better way to do this:
def conditions(obj)
if self.setor.present?
obj = obj.joins(:negocios_setores).where("setor_id = ?", self.setor.id)
end
if self.uf.present?
obj = obj.joins(localizacao: [:uf]).where("uf_id = ?", self.uf_id)
end
if self.municipio.present?
obj = obj.joins(localizacao: [:municipio]).where("municipio_id = ?", self.municipio_id)
end
if !self.lucro_liquido_min.to_f.zero?
obj = obj.where("lucro_liquido_anual BETWEEN ? and ?", self.lucro_liquido_min, self.lucro_liquido_max)
end
if !self.faturamento_min.to_f.zero?
obj = obj.where("faturamento_bruto_anual BETWEEN ? and ?", self.faturamento_min, self.faturamento_max)
end
if !self.valor_min.to_f.zero?
obj = obj.where("valor BETWEEN ? and ?", self.valor_min, self.valor_max)
end
obj
end
Does rails 4 provide something to only do the condition if the value is present instead of placing it with a NULL value?
I don't believe that there is any way to do exactly what you mentioned. I've run into the same type of concatenation of queries.
To clean up a bit and make this tighter, you can use one-line if and unless. I think this is a bit cleaner and still readable.
def conditions(obj)
obj = obj.joins(:negocios_setores).where(setor: setor) if setor.present?
obj = obj.joins(localizacao: [:uf]).where("uf_id = ?", uf_id) if uf.present?
obj = obj.joins(localizacao: [:municipio]).where("municipio_id = ?", municipio_id) if municipio.present?
obj = obj.where("lucro_liquido_anual BETWEEN ? and ?", lucro_liquido_min, lucro_liquido_max) unless lucro_liquido_min.to_f.zero?
obj = obj.where("faturamento_bruto_anual BETWEEN ? and ?", faturamento_min, faturamento_max) unless faturamento_min.to_f.zero?
obj = obj.where("valor BETWEEN ? and ?", valor_min, valor_max) unless valor_min.to_f.zero?
obj
end
I also changed the first query to use Rails style queries rather than SQL in the where.

Rails 3: Filtering merit points by category in leaderboard

The real tactical question I am facing is all categories are set as 'default' therefore if I make options[:category] = 'default' it only adds the points that have no category. Therefore if i add points to cateogry 'arin' it will not be counted to the 'default' total. So I tried to grab all tables if NOT NULL or by category but it keeps grabbing the same amount for 'arin'.
default: 20
arin: 20
Should be total of 40 if category not supplied or at 'default', if params category 'arin' then it should be 20.
Can someone help me understand the concept behind the correct SQL to get the results I am looking for?
New to rails and SQL.
def self.top_scored(options = {})
options[:table_name] ||= :users
options[:since_date] ||= 4.months.ago
options[:end_date] ||= 1.month.from_now
options[:category] ||= nil
options[:limit] ||= 10
alias_id_column = "#{options[:table_name].to_s.singularize}_id"
if options[:table_name] == :sashes
sash_id_column = "#{options[:table_name]}.id"
else
sash_id_column = "#{options[:table_name]}.sash_id"
end
# MeritableModel - Sash -< Scores -< ScorePoints
sql_query = <<SQL
SELECT
#{options[:table_name]}.id AS #{alias_id_column},
SUM(num_points) as sum_points
FROM #{options[:table_name]}
LEFT JOIN merit_scores ON merit_scores.sash_id = #{sash_id_column}
LEFT JOIN merit_score_points ON merit_score_points.score_id = merit_scores.id
WHERE merit_score_points.created_at > '#{options[:since_date]}' AND merit_score_points.created_at < '#{options[:end_date]}' AND (merit_scores.category IS NOT NULL OR merit_scores.category = '#{options[:category]}')
GROUP BY #{options[:table_name]}.id, merit_scores.sash_id
ORDER BY sum_points DESC
LIMIT #{options[:limit]}
SQL
results = ActiveRecord::Base.connection.execute(sql_query)
results.map do |h|
h.keep_if { |k, v| (k == alias_id_column) || (k == 'sum_points') }
end
results
end
end
Seems no one answered and only down voted. Here is to anyone that questions this in the future. I figured out you can split sql statements and use an if statement in rails around the SQL.
sql_query = "SELECT
#{options[:table_name]}.id AS #{alias_id_column},
SUM(num_points) as sum_points
FROM #{options[:table_name]}
LEFT JOIN merit_scores ON merit_scores.sash_id = #{sash_id_column}
LEFT JOIN merit_score_points ON merit_score_points.score_id = merit_scores.id
WHERE merit_score_points.created_at > '#{options[:since_date]}' AND merit_score_points.created_at < '#{options[:end_date]}' "
if(options[:category] != nil)
sql_query += "AND merit_scores.category = \"#{options[:category]}\" "
end
sql_query += "GROUP BY #{options[:table_name]}.id, merit_scores.sash_id
ORDER BY sum_points DESC
LIMIT #{options[:limit]} "
results = ActiveRecord::Base.connection.execute(sql_query)

Rails - Fetch results on the basis of number of params in query string

I am working on an events application where i want to filter events depending on the 3 parameters location or starts_at or ends_at in the query string. There can be any one, two or all the parameters in the query string. In i use if-else statement i need to make 6 cases which will make my code clumsy. Rather i am thinking to implement something this way:
class EventsController < ApplicationController
def index
unless params.empty?
unless params[:location].nil?
#events = Event.where("location = ?", params[:location])
end
unless params[:starts_at].nil?
unless #events.empty?
#events = #events.where("start_date = ?", params[:start_date])
else
#events = Event.where("Date(starts_at) = Date(?)", params[:starts_at])
end
end
unless params[:ends_at].nil?
unless #events.empty?
#events = #events.where("end_date = ?", params[:end_date])
else
#events = Event.where("Date(ends_at) = Date(?)", params[:ends_at])
end
end
end
end
end
But this code doesnt work since where query doen not work on an array. Can someone suggest me some solution for this..
You should be able to pass your params hash directly to where, and it will form the correct SQL based on the keys and values of that hash:
Event.where(params)
An example in the console:
1.9.3p194 :001 > puts Example.where(:location => 'here', :started_at => '2012-08-13').to_sql
SELECT "examples".* FROM "examples" WHERE "examples"."location" = 'here' AND "examples"."started_at" = '2012-08-13'
Try Following
def index
unless params.empty?
where_array, arr = [], []
if params[:location]
where_array << "location = ?"
arr << params[:location]
end
if params[:starts_at]
where_array << "start_date = ?"
arr << params[:starts_at]
end
if params[:ends_at]
where_array << "end_date = ?"
arr << params[:ends_at]
end
#events = arr.blank? ? [] : Event.where([where_array.join(" AND "), *arr])
end
end

Rails - Find or Create based on TimeStamp? possible?

In my controller I'd like to do something like the following:
#book = Book.find(:all, :conditions = > [" created_at > with in the last 1 minute "]
if #book.nil?
# Just incase we didn't create a book, we'll initialize one
#book = Book.create()
end
#chapters = #book.chapters.build etc.............
* In sum, when the user is uploading a chapter, if they've recently created a book, I want the chapter to automatically go to that book and to make a new book.
Thoughts? thank you all
Hi Your code may be something like
time = Time.now
#book = Book.find(:all, :conditions = > [" created_at >= '#{Time.utc(time.year, time.month, time.day, time.hour, time.min - 1)}'"]) // .first if you're sure that it'll return just one record
if #book.blank? //.blank? not .nil? because the result of find is [] not nil
# Just incase we didn't create a book, we'll initialize one
#book = Array.new() //if you're sure that find'll return just one book you may don't change your code here
#book.first = Book.create()
end
//if you're sure that find'll return just one book you may don't change your code here
#book.each do |book|
#chapters = #book.chapters.build etc.............
end
if you're looking for a book created by some user you must pass user_id to this method and your conditions'll be
:conditions = > [" created_at >= '?' AND author_id = ?", Time.utc(time.year, time.month, time.day, time.hour, time.min - 1), params[:author_id]])

Resources