I have a fairly complex method in my controller that basically outputs data to be used in a view to create a donut graph.
def courses_allocated
course_id = params[:course_id];
client_id = params[:client_id];
override_client_id = get_client_id_for_current_user
unless override_client_id.nil?
client_id = override_client_id
end
category_course_enrollments = CourseEnrollment.select("course_categories.title, COUNT(*) as count").
joins("INNER JOIN courses ON course_enrollments.course_id = courses.id").
joins("INNER JOIN course_categories ON courses.course_category_id = course_categories.id").
group("course_categories.id").
order("course_categories.title")
course_enrollments = CourseEnrollment.select("COUNT(*) as count, course_enrollments.course_id, courses.title").
joins("INNER JOIN courses ON course_enrollments.course_id = courses.id").
joins("INNER JOIN course_categories ON courses.course_category_id = course_categories.id").
group("course_enrollments.course_id").
order("course_categories.title")
unless course_id.blank?
category_course_enrollments = category_course_enrollments.where("course_enrollments.course_id = ?" , course_id.to_i)
course_enrollments = course_enrollments.where("course_enrollments.course_id = ?" , course_id.to_i)
end
unless client_id.blank?
category_course_enrollments = category_course_enrollments.where("courses.client_id = ?", client_id)
course_enrollments = course_enrollments.where("courses.client_id = ?", client_id)
end
#category_data = []
#course_assigned_data = []
#course_assigned_detail_data = []
category_course_enrollments.each do |category_course_enrollment|
#category_data.push([category_course_enrollment.title, category_course_enrollment.count]);
end
course_enrollments.each do |course_enrollment|
not_started = CourseEnrollment.select("COUNT(patient_id) AS total_not_started").
where('started IS NULL').
where('course_id = ?', course_enrollment.course_id).first.total_not_started
in_progress = CourseEnrollment.select("COUNT(patient_id) AS total_in_progress").
where('started IS NOT NULL').
where('completed IS NULL').
where('course_id = ?', course_enrollment.course_id).first.total_in_progress
completed = CourseEnrollment.select("COUNT(patient_id) AS total_completed").
where('completed IS NOT NULL').
where('course_id = ?', course_enrollment.course_id).first.total_completed
#course_assigned_data.push([course_enrollment.title, course_enrollment.count]);
#course_assigned_detail_data.push({'name'=>course_enrollment.title + " Not Started", 'y'=> not_started, 'color'=>'#ff8800'});
#course_assigned_detail_data.push({'name'=>course_enrollment.title + " In Progress", 'y'=> in_progress, 'color'=>'#0088ff'});
#course_assigned_detail_data.push({'name'=>course_enrollment.title + " Completed", 'y'=> completed ,'color'=>'#44cc44'});
end
end
The View for the donut graph (besides the input for a form is:)
<div id="reportcoursesallocatedgraph">
</div>
<script type="text/javascript">
new IS.ReportCoursesAllocated('Course Allocated', <%= raw(ActiveSupport::JSON.encode(#category_data)); %>, <%= raw(ActiveSupport::JSON.encode(#course_assigned_data)); %>, <%= raw(ActiveSupport::JSON.encode(#course_assigned_detail_data)); %>, 'reportcoursesallocatedgraph');
</script>
I want to reuse the logic from courses_allocated from a method in the same class; def dashboard. (The dashboard method basically creates a bunch of different graphs)
Should I make a private method that they can both share?
If the logic is identical, then you can just alias dashboard to courses_allocated. To do that, you can put this right below the courses_allocated action method.
alias dashboard courses_allocated
Related
I have a method full_name in owner.rb, I want to sort owner asc and desc in properties index, either it does asc or will do desc, but in this case, I have tried many ways to sort this but none of this is working, I'm quite new using ransack, can anyone please let me how to make this work with associated relations, here property belongs to owner and owner has many properties.
def full_name
[first_name,last_name].join(" ").squish
end
which I am calling in properties index
td.special-td
- unless property.owner.nil?
a href=manager_user_owner_petty_cash_path(property.owner.id) #{property.owner.full_name}
I am trying to apply sort_link on the table column:
th = sort_link(#q, :owners_full_name, "Landlord")
while this sorting is not working here is my properties index controller
def index
authorize Property
if !current_user.manager?
unit_ids = current_user.unit_ids
total_units_limit = " units.id in (#{unit_ids.join(',')}) or properties.user_id = #{current_user.id} "
properties_ids = company.properties.joins(:units).where(total_units_limit).group(:id).pluck(:id).join(",")
if properties_ids.blank?
properties_ids = 0
end
owners_limit = " properties.id in (#{properties_ids}) "
end
pagination_limit_check
#q = company.properties.joins("left join units on units.property_id = properties.id ").includes(:units, :owner, :contracts, :tags)
.where(total_units_limit).ransack(params[:q])
#q.sorts = 'name asc' if #q.sorts.empty?
self.properties = #q.result(distinct: true).page(params[:page]).per(#page_limit)
self.owners = Owner.joins(:properties).where(owners_limit)
end
I have a controller with 2 queries :
def index
#invoices = current_company.invoices.order(billed_at: :desc)
#user_invoices = current_user.invoices.order(billed_at: :desc)
end
in my view I have a table with a if to render the table and sometimes I have both to display,
I have a column date in this table,
How can I sort this table by date ?
Simple Rails way - just connect them and sort:
def index
#invoices = current_company.invoices.order(billed_at: :desc)
#user_invoices = current_user.invoices.order(billed_at: :desc)
#all_invoices = (#invoices + #user_invoices).sort_by {|a| a.created_at}.reverse
end
In your view:
- #all_invoices.each do |invoice|
= invoice.id
So simple!
Alternatively if you want to display either company OR user invoices:
def index
if current_company.present?
#invoices = current_company.invoices.order(billed_at: :desc)
elsif current_user.present?
#user_invoices = current_user.invoices.order(billed_at: :desc)
end
end
You could do a union of the two queries and order that...
def index
invoices = current_company.invoices
user_invoices = current_user.invoices
#all_invoices = Invoice.from("(#{invoices.to_sql} UNION #{user_invoices.to_sql}) AS invoices").order(billed_at: :desc)
end
Then you just iterate through #all_invoices. You could test if the invoice is company or user by an if statement if invoice.company == current_company
I've got an array of columns that I want to loop through and optionally chain an or query onto an ActiveRecord query chain. I can get it to work, but the resulting query appends the or onto the query chain, therefore making the columns in my inital query optional. Here's my class:
class Claim
class MatchingAttributeFinder
ATTRIBUTE_GROUPS_TO_MATCH = [
["teacher_reference_number"],
["email_address"],
["national_insurance_number"],
["bank_account_number", "bank_sort_code", "building_society_roll_number"],
].freeze
def initialize(source_claim, claims_to_compare = Claim.submitted)
#source_claim = source_claim
#claims_to_compare = claims_to_compare
end
def matching_claims
claims = #claims_to_compare.where.not(id: #source_claim.id)
ATTRIBUTE_GROUPS_TO_MATCH.each do |attributes|
vals = values_for_attributes(attributes)
next if vals.blank?
concatenated_columns = "CONCAT(#{attributes.join(",")})"
claims = claims.or(
Claim.where("LOWER(#{concatenated_columns}) = LOWER(?)", vals.join)
)
end
claims
end
private
def values_for_attributes(attributes)
attributes.map { |attribute|
#source_claim.read_attribute(attribute)
}.reject(&:blank?)
end
end
end
The generated SQL looks like this:
SELECT "claims".* FROM "claims" WHERE (((("claims"."submitted_at" IS NOT NULL AND "claims"."id" != 'a7b25b99-4477-42b1-96ab-8262582c5541' OR (LOWER(CONCAT(teacher_reference_number)) = LOWER('0902344'))) OR (LOWER(CONCAT(email_address)) = LOWER('genghis.khan#mongol-empire.com'))) OR (LOWER(CONCAT(national_insurance_number)) = LOWER('QQ891011C'))) OR (LOWER(CONCAT(bank_account_number,bank_sort_code,building_society_roll_number)) = LOWER('34682151972654123456789/ABCD')))
But what I actually want is more like this:
SELECT "claims".* FROM "claims" WHERE "claims"."submitted_at" IS NOT NULL AND "claims"."id" != 'd6a53b4d-c569-49e6-a2ea-ac44b69b0451' AND (LOWER(concat(teacher_reference_number)) = LOWER('0902344') OR LOWER(concat(email_address)) = LOWER('genghis.khan#mongol-empire.com') OR LOWER(concat(national_insurance_number)) = LOWER('QQ891011C') OR LOWER(concat(bank_account_number,bank_sort_code,building_society_roll_number)) = LOWER('34682151972654123456789/ABCD'))
Is there any way to set up something like an empty scope that I can chain my OR queries to?
Try chaning all the "or" together first and then chain the original query
def matching_claims
claims = #claims_to_compare.where.not(id: #source_claim.id)
ors = nil
ATTRIBUTE_GROUPS_TO_MATCH.each do |attributes|
vals = values_for_attributes(attributes)
next if vals.blank?
concatenated_columns = "CONCAT(#{attributes.join(",")})"
aux = Claim.where("LOWER(#{concatenated_columns}) = LOWER(?)", vals.join)
if ors.nil?
ors = aux
else
ors = ors.or(aux)
end
end
claims.merge(ors)
end
#counseling = Counseling.ransack(params[:q])
#counselings = #counseling.result.joins('RIGHT JOIN "subjects" ON "subjects"."id" = "counselings"."subject_id"')
#result = {}
#result[:data] = #counselings.group(row_condition).count
Blockquote
def self.create_case_sql_for_nested_tree2(foreign_key)
modelClass = foreign_key.sub(/_id3$/, '').camelize.constantize
#when_then_conditions = modelClass.roots.map do |o|
o.children.map do |c|
c.children.map do |g|
idlist = g.self_and_descendants.pluck(:id)
"WHEN subject_id IN(#{idlist.join(',')}) THEN #{g.id}"
end
end
end
"CASE #{#when_then_conditions.join(' ')} ELSE null END"
end
According to your comment, You want to join Counseling and Subject model and count the subject_id. I think you can do it like this,
Counseling.joins(:subject).count(:subject_id)
If you want to put any where condition you can do it like this,
Counseling.joins(:subject).where("some condition").count(:subject_id)
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