Sum attributes of each related record in Rails? - ruby-on-rails-3

In my Rails 3 I have the following models:
Animal
Claim
Exclusion
The model relations are as follows:
Animal has_one exclusion
Animal has_many claims
Claim has_one Animal
Exclusion belongs_to Animal
In the exclusions table I have the following columns:
animal_id, con1, con2, con3, con4, con5
In the claim table I have the following columns:
animal_id, con1, con2, con3, con4, con5, description, date
An exclusion has_one animal and a claim has_one animal. Animal has_many claims and has_one exclusion.
So, the user creates a claim which adds a value alongside each of the con* columns. How can I (in the Animal view) sum the total claimed for each condition?
For example; in my Animal view:
Condition 1 = 10.00
Condition 2 = 20.00
Condition 3 = 0.00
Condition 4 = 200.00
Condition 5 = 232.22
The values alongside the above conditions are taken from the following claims:
ID, con1, con2, con3, con4, con5, animal_id
-------------------------------------------
1, 5.00, 10.00, 0.00, 100.00, 200.00, 123
2, 5.00, 10.00, 0.00, 100.00, 32.22, 123
So the values of each condition is summed up across all claims belonging to the current animal.
Is this possible?

If your current animal is called #animal, then you can sum the values for a particular condition across all claims using the sum method:
con1_sum = #animal.claims.sum(:con1)
In your view, you could do something like this:
Condition 1 = <%= #animal.claims.sum(:con1) %>
Condition 2 = <%= #animal.claims.sum(:con2) %>
Condition 3 = <%= #animal.claims.sum(:con3) %>
Condition 4 = <%= #animal.claims.sum(:con4) %>
Condition 5 = <%= #animal.claims.sum(:con5) %>
It would probably make more sense to calculate these in the controller action rather than directly in the view, but anyway you get the idea.

Related

Rails linking multiples row's id in a table to a single row in another table SQL

I'm making a calendar app in which the user can create multiple calendar and add multiple entries to each different calendar in Rails. For instance, I have the following table
Entry
id description
----------------------------------------------------
1 go shopping
2 go to cinema
3 do homework
Calendar
id entry_id
----------------
1 1, 3
2 2
3 1, 2, 3
What would be the association/solution if I want to get all the entries from a row (in array?) in the calendar and how do would I add a new entry to the row? (I looked at the has_and_belongs_to_many association but it seems to require a third table which isn't as direct as having multiple ids assigned to a single row...)
If you don't want to have to do crazy joins later you would probably want to have a join table. Yes the third table is a good idea here.
class Entry < ActiveRecord::Base
has_many :calendars, through: :scheduling
end
class Calendar < ActiveRecord::Base
has_many :entries, through: scheduling
end
class Scheduling < ActiveRecord::Base
belongs_to :entry
belongs_to :calendar
end
Then tables look like this:
entires
id:integer
description:string
calendars
id:integer
schedulings
id:integer
calendar_id:integer
entry_id:integer
And your ActiveRecord queries look like this:
Calendar.find(3).entries.ids #=> [1, 2, 3]
Entry.find(1).calendars.ids #=> [1, 3]
The rails guide also provide a great example:
http://guides.rubyonrails.org/association_basics.html#choosing-between-has-many-through-and-has-and-belongs-to-many

Rails how to group_by data with conditions?

I have two tables , book:
book:
id
book_name
brand_id
belongs_to :brand, foreign_key: "brand_id"
and brand:
brand:
id
brand_name
has_many :books
I want to group data from book and get results like following:
id brand_name count
1 b1 20
2 b2 32
and display on view, use params to get values and insert into collection_select like:
<%= collection_select('', :brand_id, #brands , #brands.id, #brands.name + '(' + #brands.count + ')' , {:prompt => 'please select!'} ) %><br>
I want the dropdown list looks like :
b1(20)
b2(32)
how can I do that?
I tried #brands = Book.group(:brand_id).count
but it's only shows:
'1':20
'2':32
I don't know how to get value via params, and there is no brand_name, please give me some suggestions!
One of possible solutions to your problem is:
#brands = Brand.joins(:books).select("brands.id, brands.name, COUNT(books.id) as cnt").group("brands.id, brands.brand_name")
Now you can convert it to collection, which you can be used by select helper:
collection = #brands.map{|b| [ "#{b.name} (#{b.cnt})", b.id ] }
and use it in your form:
select 'book', 'brand_id', collection
Hey you can try this way. Just sure with your model name and table name in query. It returns you a active record array then you can manage in according to your collection select hash:
brands = Book.joins(:brand).select("brands.id as id, brands.name as brand_name,count(*) as count").group(:brand_id)
You can create your required array by
#brands = brands.collect{|o| ["#{o.brand_name}(#{o.count})",o.id]}
After that you can passed this array to select tag as:
<%= select_tag 'brand_id' , options_for_select(#brands) %>

How to select only unique entries from a join table

I would like to make my block of code more efficient. I have two models and a join table for them. They both have a has_many :through relationship. Some parts belong to multiple groups, some only belong to one. I need to get the records that belong to only one group and in the most efficient manner as there are thousands of parts. Here are my models:
part.rb
class Part < ActiveRecord::Base
attr_accessible :name,
:group_ids
has_many :part_groups, dependent: :destroy
has_many :groups, through: :part_groups, select: 'groups.*, part_groups.*'
end
group.rb
class Group < ActiveRecord::Base
attr_accessible :name,
:part_ids
has_many :part_groups, dependent: :destroy
has_many :parts, through: :part_groups, select: 'parts.*, part_groups.*'
end
part_group.rb
class PartGroup < ActiveRecord::Base
attr_accessible :part_id,
:group_id
belongs_to :part
belongs_to :group
end
What I would like to be able to do is get all the parts that belong only to Group A and only to Group B, but not ones that belong to both A & B. After struggling with this for hours and getting nowhere I'm using this as a stop gap:
#groupA = []
#groupB = []
Part.all.each do |part|
if part.group_ids.length == 1
if part.group_ids.first == 1
#groupA.push(part)
elsif part.group_ids.first == 2
#groupB.push(part)
end
end
end
This obviously isn't scalable as there will be many groups. I've tried various methods of join and include that I've been googling but so far nothing has worked.
I am also new to rails , So as far i understand this is the structure of your tables.
parts
Id | Name
groups
Id | Name
part_groups
Id | part_id | group_id
So you can do the following,
Group.find(1).parts // Parts belong to group A
Group.find(2).parts // Parts belong to group B
so this may give parts that belong to other groups also.
Objective is to get parts that belongs only to group A and only to group B
Try for
Group.find(1).parts.collect{|row| row if row.groups.count==1}.flatten
I think this is better approach than yours , because am traversing only those parts which belong to group1.
The raw sql for this could look like
select parts.* from parts
inner join part_groups on parts.id = part_groups.part_id
left outer join part_groups as group_b on group_b.part_id = parts.id and group_b.group_id = 456
where group_b.id is null and part_groups.group_id = 123
Assuming that group a had id 123 and group b had id 456.
What this does is try to join the part_groups table twice (so an alias needs to be used the second time), once where group_id matches group A and once against group B. The use of the left join allows us to require that the second join (against B) produces no rows.
Activerecord doesn't provide much assistance for this, other than allowing you to pass arbitrary sql fragments to joins, so you end up with something like
Part.select("parts.*").
.joins(:part_groups).
.joins("left outer join part_groups as group_b on group_b.group_id = #{groupb.id} and group_b.part_id = parts.id").
.where(:part_groups => {:group_id => groupa.id}).where("group_b.id is null")
Arel (which underpins the query generation part of active record) can generate this sort of query but this isn't exposed directly.

ActiveRecord : find associated records with ALL conditions

I am trying to perform an activerecord query that essentially does the below.
I have 3 models in a many-to-many relationship
class Item < ActiveRecord::Base
has_many :item_modifiers, dependent: :destroy
has_many :modifiers, through: :item_modifiers
end
class ItemModifier < ActiveRecord::Base
belongs_to :item
belongs_to :modifier
end
class Modifier < ActiveRecord::Base
has_many :item_modifiers
has_many :items, through: :item_modifiers
end
Now I want to find all items that have modifiers with IDs 1 and 2
I have tried several things like:
Item.includes(:modifiers).where(modifiers: {id: 1}).where(modifiers: {id: 2})
This fails because it searches for modifiers where ID = 1 AND ID = 2 which is always false.
This also doesn't work
Item.includes(:modifiers).where(modifiers: {id: [1, 2]})
Because this does an IN (1, 2) query so it returns items with modifiers of either 1 or 2. I want items that have any modifiers as long as they have AT LEAST 1 modifier with ID 1 and AT LEAST 1 modifier with ID 2
I seem to be missing something quite simple but I just can't get my head around it.
Thanks in advance.
It could like:
Item.joins(:item_modifiers).where("item_modifiers.modifier_id=1 OR
item_modifiers.modifier_id=2").group("items.id").having("COUNT(item_modifiers.id)=2")
If write in plain SQL, it could be:
SELECT I.*, COUNT(IM.id) FROM items as I INNER JOIN item_modifiers AS IM on I.id=IM.item_id
WHERE IM.modifier_id=1 OR IM.modifier_id=2 GROUP BY I.id HAVING COUNT(IM.id)=2
It will get all the items with its modifers' id include 1 and 2. Maybe in different DB, the statement need a slight change.

Rails 3 Joins Active Record query

I am stuck at join two tables using active record 3.0
Table A
id name
1 xcv
Table B #a_id is foreign_key
id date a_id
1 9/15 1
How to query using active record to get output as
id date a_name
1 9/15/ xcv
When I do
B.joins(:A)
in Model B than I get following sql
SELECT "B".* FROM "B" INNER JOIN "A" ON "A"."ID" = "B"."A_ID"
When I query it on our DB it give correct output but rails logger has wrong output
#<B id: 1, date"9/15/11", a_id: 2>
I want is
#<B id: 1, date"9/15/11", a_name: xcv>
Relation is as follow
A has_many :B
B belongs_to :A
Any help is really appreciated..
I believe what you're looking for is
#bees = b.includes(:a).all # this will join A and eager load your A's
then on your view, you can output
<% #bees.each do |b| %>
<%= b.a.name %>, <%= b.a.date %>
<% end %>
or work with it in a similar manner