Rails3 help with joins scope - ruby-on-rails

Have simple Order - Item app. No cart. Need help with joined scopes for my reports.
Item is polymorphic (belongs_to :itemable, :polymorphic => true) with Products, Services and Policies. Policies belongs to Vendor.
Goal is list out how much was sold by Vendor but still be able to use the scopes for Orders as seen below.
Scopes in my Orders model
scope :closed_today, lambda { where("closed_date IS NOT ? AND closed_date >= ? AND closed_date < ?", nil, Time.now.midnight, Time.now.midnight.tomorrow)}
scope :closed_yesterday, lambda { where("closed_date IS NOT ? AND closed_date >= ? AND closed_date < ?", nil, Time.now.midnight.yesterday, Time.now.midnight)}
...
Something like - Guess in Orders Model?
scope :with_policies, joins(:items).where(:itemable_type => "Policy")
And Final Result being able to group by vendor and get amounts sold.
<% for v in #orders.closed_today.with_policies.group("itemable.vendor_id") %>
<%= v.somehow_get_to.vendor.name %> Sold: <%= v.somehow_get_to.collect.sum(&:price) %>
Price is the item field that holds how much that item sold for.
I know you can't group as shown above, so any pointers on how to do that would be great. Would like to avoid adding vendor_id to my Items table.
UPDATE
Here is what I ended up doing.
Added vendor_id to items. Made my life easier. Sure this is a better way of doing this.
In my Items model
scope :in_orders_with, lambda { |orders, type| where('itemable_type IS ?', type).joins(:order) & orders }
In my view (since #orders.closed_today is actually passed in from another view.)
<% orders = #orders.closed_today %>
<p>
<% #items = Item.in_orders_with(orders, "Policy") %>
<% if !#items.blank? %>
<% #items.group_by{ |o| o.vendor }.each do |vendor, items| %>
<%= vendor.name %> <br />Qty Sold:<%= items.count %> Dollars Sold:<%= items.collect.sum(&:price) %><br /><br />
<% end %>
<% else %>
Nothing to report from Policies<br />
<% end %>
</p>

<% #orders.closed_today.with_policies.group_by{|o| o.itemable.vendor}.each do |vendor, orders| %>
<%= vendor.name %> SOLD: <%= orders.sum(&:price) %>
<% end %>

Related

Rails 4 - How to populate an array through a form

I have three tables: illness, symptom and a secondary table to link the other two on a has_many through: relationship.
I wish to implement a system where users type in their symptoms and receive a list of possible illnesses.
Using the code below I can use find(1,2), for example, to show all illnesses that have symptoms 1 and 2 simultaneously. However, I want these two constants to be user-supplied data fed through a form. I'm somewhat new to RoR so I don't know how to do this.
symptoms = Symptom.find(params[:symptom_ids]) # symptom_ids is an array of ids
illnesses = Illness.joins(illness_symptoms: :symptom)
.where("symptoms.id in (?)", symptoms)
.group("illnesses.id")
.having("count(illnesses.id) >= ?", symptoms.length)
In the model:
scope :with_symptoms, -> (symptoms) { joins(illness_symptoms: :symptom)
.where("symptoms.id in (?)", symptoms)
.group("illnesses.id")
.having("count(illnesses.id) >= ?", symptoms.length) }
I use these with Illness.with_symptoms(Symptom.find(1,2)) (I'm looking for a way to replace 1,2 with user-supplied data).
You can do something like this in a form:
<% form_tag some_path do %>
<% #symptoms.each do |symptom| %>
<%= label_tag do %>
<%= check_box_tag "symptom_ids[]", symptom.id %>
<%= symptom.name %>
<% end %>
<% end %>
<% end %>
User will be able to use checkboxes to choose symptoms.

listing data dependant on associated database

Wasn't sure how to title this question but here it goes.
I have two tables, Hotdesks and Bookings. Users can book a hotdesk.
In my controller I have an array #eastdesks containing all desks with a location of "East".
What I would like to do is to check which of these desks have been booked and display a list of available desks. This is my controller:
#eastdesk = Hotdesk.order("code ASC").where(:location => "East")
#booking = Booking.all
And this is my code so far:
<% #eastdesk.each do |ed| %>
<% #booking.each do |b| %>
<% if b.date == Date.today && b.type == "Hot Desk" %>
<% if b.desk == ed.code %>
<%= ed.code %> (Booked)
<% end %>
<% end %>
<% end %>
<% end %>
This ONLY shows those that have been booked.
I appreciate it is very ugly because I have been playing around. It is quite confusing but the t tables are associated vie the 'desk' column in bookings and the 'code' column in eastdesk. (i.e. booking with desk 553 will link to the desk with code 553) Hope that makes sense. Thanks for the help
EDIT ----
At the moment there are 2 desks in #eastdesk array (E90 and E23). The E90 desk has been booked for today and the E23 desk has not been booked at all. For the code above I am getting the following output:
E90 (Booked)
What I want to show is the desks that have NOT been booked. My Hotdesk model consists of:
has_many :bookings
I was thinking of adding the following to my bookings model but I am not sure as there ar different types of bookings and not all of them belong to a hot desk.
belongs_to :hotdesks
You can create an array holding 'Desk Codes' from booking table and use 'include?' method to check if this array contains the 'desk' value of #eastdeck.
Possible Solution:
#booking.map { |b| #booking_codes.push b.desk } // Creating a temporary array holding 'desk' from #booking
View:
<% #eastdesk.each do |ed| %>
<% #booking.each do |b| %>
<% if b.date == Date.today && b.type == "Hot Desk" && #booking_codes.include? b.desk %>
<%= ed.code %> (Booked)
<% end %>
<% end %>
<% end %>
PS: This may not be the nicest solution, but it may help :)

Rails Form element to convey two values

I have a form that takes bookings for an event for people. The form displays events vertically, and a name & checkbox for each of the possible people next to each event.
How should I best convey the two pieces of information that i need per checkbox? that is, the event_id and the person_id
I'm not totally sure wether I got you right. This is the model I assume you're talking about:
# event.rb
class Event
has_many :people
scope :possible_people, -> { #whatever .. }
end
# person.rb
class Person
belongs_to :event
end
# events_controller.rb
class EventsController
def index
#events = Event.all
end
end
And this might be a possible solution to change an events relation to people:
# index.html.erb
<ul id="events">
<% #events.each do |event| %>
<li class="event">
<%= form_for #event do |form| %>
<% event.possible_people.each do |person| %>
<%= check_box_tag "event[person_ids][]", person.id, #event.people.include?(person) %>
<% end %>
<%= f.submit_tag 'Save Event' %>
<% end %>
</li>
<% end %>
</ul>
The important part is <%= check_box_tag "event[person_ids][]", person.id, #event.people.include?(person) %> where you actually change the the relation of a specific person to the event.
Good luck ;)
Well, you can try out something like below line, I am assuming you have a multiselect checkboxes and i am passing a Hash of event_id => plate_id as value to checkbox.
<%= check_box_tag 'booking[event_people_ids][]', {booking.event_id => booking.plate_id} %>
You will get the value in params as:
booking => {event_people_ids =>["{"72"=>"3"}}
I ended up doing this:
<%= check_box_tag "booking[]", "#{event.id}-#{person.id}" %>
and then in then to process them:
params[:booking].each do |booking|
booking = booking.split('-')
a = {
:booking_id => #booking.id,
:person_id => booking[1],
:event_id => booking[0]
}
Appointment.create(a)
end
I was hoping for a more railish way to do it but this works.

grouping children by parent attribute

Here's what I am trying to achieve:
Group_x.name
member1.name -- member1.join_date -- etc
member2.name -- member2.join_date -- etc
...
Group_y.name
member1.name -- member1.join_date -- etc
member2.name -- member2.join_date -- etc
...
What I'm going for is really very similar to this although the implementation there doesn't work for me.
I've gotten this far in my controller:
def index
# https://stackoverflow.com/a/17835000/2128691
#user_group_ids = current_user.student_groups.map(&:id)
#students = Student.where('student_group_id IN (?)', #user_group_ids)
# https://stackoverflow.com/a/10083791/2128691
#students_by_group = #students.uniq {|s| s.student_group_id}
#title = "All students"
end
and calling the following in my view -
<% #students_by_group.all.each do |x| %>
<p>
<%= "#{x}" %>
</p>
<% end %>
gives me a list of all student objects. if i call <%= "#{x.name}" %> or <%= "#{x.created_at}" %>, etc, I get the correct information, and everything is great.
But now that I have all this information, how can I put the group.name (in my code it would be x.student_group.name) as a header for all of the students for which that group_name is true?
I think you need to use group_by on #students_by_group like this:
#students_by_group = #students_by_group.group_by { |s| s.student_group }
This would return a hash with the keys being the student group objects and the values being the students that belongs to this group, then you can do this in your view:
<% #students_by_group.each do |group, students| %>
<h3><%= group.name %></h3>
<% students.each do |x| %>
<p>
<%= "#{x}" %>
</p>
<% end %>
<% end %>
As an additional note, the group_by would fire a query for each student, so you may want to eagerly load the student group for each student like this for some performance gain:
#students = Student.where('student_group_id IN (?)', #user_group_ids).includes(:student_group)

group_by display belongs_to 'name' followed by has_many 'items'

I'm trying to display group name (product_group) followed by the items (product) in each group.
<% #products.group_by(&:product_group_id).each do |s|%>
<!--need to get group name here ->
<% s[1].each do |d|%>
<%= d.product_name%>
<br>
<%end%>
<%end%>
rails 2.3.8
First, I strongly recommend using two variables in your block. When you use one variable, group_by sets the variable to an array of the pair of values which should be set as two variables. It will be much more clear code than indexing the pair with [1] for the group.
One way is that the first part of the pair will be the id, so you can do a find.
<% #products.group_by(&:product_group_id).each do |product_group_id, products|%>
<!--need to get group name here -->
<%= ProductGroup.find(product_group_id).name %>
<% products.each do |product|%>
<%= product.product_name%>
<br>
<% end %>
<% end %>
Another way, is since you have an array of at least on product in the group, you can call the product_group association on the first element of the array.
<% #products.group_by(&:product_group_id).each do |product_group_id, products|%>
<!--need to get group name here -->
<%= products[0].product_group.name %>
<% products.each do |product|%>
<%= product.product_name%>
<br>
<% end %>
<% end %>
You can also delegate the name to the product group.
class Product
belongs_to :product_group
delegate :name, :to => :product_group, :prefix => true, :allow_nil => true
end
<%= products[0].product_group_name %>
Group by needs two variables in the block declaration. The first for the thing you are grouping by, and the second to hold the things in each of the groups.
<% #products.group_by(&:product_group_id).each do |group_id, group_products| %>
Group ID: <%= group_id %>
<br>
Products:
<% group_products.each do |product| %>
<%= product.product_name %>
<% end %>
<% end %>

Resources