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
Related
How can I get unique values from column in the table?
For example, I have this Products table:
ID NAME CATEGORY
1 name1 1st_cat
2 name2 2nd_cat
3 name3 1st_cat
Here I want to get only 2 values - 1st_cat and 2nd_cat:
<%Products.each do |p|%>
<%=p.category%>
<%end%>
Two more ways:
Product.select(:category).map(&:category).uniq # Ruby does the work
Product.uniq.pluck(:category) # DB does the work (superior)
For Rails >= 5.1 use:
Product.distinct.pluck(:category) # DB does the work (superior)
...because Relation#uniq was deprecated.
I think you can do this:
<% Products.select("DISTINCT(CATEGORY)").each do |p| %>
<%= p.category %>
<% end %>
Source: http://guides.rubyonrails.org/active_record_querying.html#selecting-specific-fields
This does all the work in the database server. The result is a simple array.
<% Product.distinct(:category).pluck(:category).each do |category|
<%= category %>
<% end %>
Rails will generate SQL that works on any database (Postgres, MySQL, etc).
SELECT DISTINCT "products"."category" FROM "products"
I suggest to use Products.all.distinct.pluck(:category) because uniq has been deprecated since rails 5 and it will be removed on rails 5.1
Try this (in the rails console)
Product.group(:category)
Product.group(:category).each { |p| p.name }
For postgres
<% Product.select("DISTINCT ON (category) *").each do |category|
<%= category %>
<%= name %>
<% end %>
Update
even better
<% Product.select(%(DISTINCT ON (category) "#{Product.table_name}".*)).each do |category|
<%= category %>
<%= name %>
<% end %>
because it can return wrong columns when you do joins (e.g. returns id column from joined table, but not products)
If you or anyone want to get two or more attributes from a table like products, based on a distinct feature of an attribute, only this solution will help you for Rails >= 5.1
distinct_products = Product.select("DISTINCT ON (category) *")
# it's an active record relation class.
> distinct_products.class
=> Product::ActiveRecord_Relation
N.B. Don't use .pluck() on the distinct_products. It will reselect from the products table and the distinct feature will not work anymore.
Needed to get unique output and was trying the 'uniq' method unsuccessfully. Tried several solutions posted here unsuccessfully. I'm using devise which gives me access to the current_user method and working with two tables, one being a join (an item has_many :things).
This solution ultimately worked for me :
#current_user.things.select(:item_fk).distinct.each do |thing|
<%= thing.item.attribute %>
<% end %>
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) %>
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.
I have two models: Product and Categories. They have a HABTM relationship.
At products form i have:
<% Category.find(:all).each do |c| %>
<%= check_box_tag 'product[category_ids][]', c.id, #product.category_ids.include?(c.id) %> <%=c.name%>
<% end %>
It works perfectly but when a categories_products record is created, the created_at field is empty ( 0000-00-00 00:00:00 ).
How can i make Rails create/update those fields?
Thanks.
I have many items and many users in a database. A user can set a status to the various items. The three tables are (they have been simplified in this explanation) users, statuses, items. The models are shown below.
class Item < ActiveRecord::Base
has_many :statuses
end
class Status < ActiveRecord::Base
belongs_to :user
belongs_to :item
end
class User < ActiveRecord::Base
has_many :statuses
end
The controller
class ItemController < ApplicationController
def index
#items = Item.all
end
end
The view (this has been simplified, in my code I actually generate a form for the status so the user can create/modify their status but in the example below I'm just making as if the status is being printed out as text):
<th>Item ID</th>
<th>Item Status</th>
...
<% #items.each do |item| %>
<td><%= item.id %></td>
<% status = item.statuses.where(:user_id => current_user.id) %>
<td><%= status.first.status %></td>
<% end %>
Here are the queries generated by Rails:
Item Load (0.3ms) SELECT `items`.* FROM `items` ORDER BY id asc
SQL (0.2ms) SELECT COUNT(*) FROM `statuses` WHERE (`statuses`.item_id = 1) AND (`statuses`.`user_id` = 103)
SQL (0.2ms) SELECT COUNT(*) FROM `statuses` WHERE (`statuses`.item_id = 2) AND (`statuses`.`user_id` = 103)
Status Load (0.1ms) SELECT `statuses`.* FROM `statuses` WHERE (`statuses`.item_id = 2) AND (`statuses`.`user_id` = 103) LIMIT 1
SQL (0.2ms) SELECT COUNT(*) FROM `statuses` WHERE (`statuses`.item_id = 3) AND (`statuses`.`user_id` = 103)
All the items are selected in one SQL query which I think is good. Then it seems the SELECT COUNT (*) query is executed, if a status is found then that status is fetched using another SQL query, this happens for each item.
Guessing there is a much better way of going about this, when I have a few hundred items the number of SQL queries being carried out is huge! If anyone has any tips for how they would go about this I'd be interested to hear.
Thanks.
The solution is to include the statuses when you build the items.
#items = Item.includes(:statuses).all
And then use a select method to return the relevant status.
item.statuses.select {|s| s.user_id => current_user.id}
The rails magic sometimes results in these crazy queries, since item.statuses can be interpreted as either an array of status objects, or an ActiveRecord Relation.
When you call the where method on item.statuses, it defaults to ActiveRecord Relation behaviour, and builds a new SQL query. If you call select, item.statuses behaves as an array.
This is also the case for methods like sum. Very annoying!