Rails 3 how to do a query with a habtm association - ruby-on-rails

I need to dump a set of Awards into a instance variable:
#corp = Award.find(:all, :conditions => ["award.category_id = ?", "2" ])
Award <= => AwardsCategories <= => Categories
I am trying to find All the Awards that have a Category of X
The interesting piece I am noticing is that my Award.category_id is nil but the AwardsCategory.category_id and award_id are both set.
The error is returning is:
ActiveRecord::StatementInvalid in PagesController#award_cat
PGError: ERROR: missing FROM-clause entry for table "award"
LINE 1: SELECT "awards".* FROM "awards" WHERE (award.category_id = ...
^
: SELECT "awards".* FROM "awards" WHERE (award.category_id = '2')
Any ideas and merry christmas

With a habm award doesn't need a category_id (after all, if it was used, how could an award have multiple categories?)
You need to join the award_categories table and put conditions on award_categories.category_id. Obviously if you have an actual category handy, you can just do
category.awards

Related

Update_all query with joins in rails console

I have an trackers table and applications tables
application.rb
has_many :trackers
tracker.rb
belongs_to :application
What I trying to do is update the check_in_date in the trackers table to be query to begin_date in the applications tables only for those records which have check_in_date is equal to "2019-05-30".
I am trying to run the command below but I am getting an error.
Tracker.joins(:application).where("check_in_date = ?", "2019-05-30").update_all("tracker.check_in_date = application.begin_date")
error
ActiveRecord::StatementInvalid (PG::UndefinedTable: ERROR: missing FROM-clause entry for table "application")
Any idea where i am going wrong.
Maybe try this:
Note I have no idea if this will work so don't do it in production unless you can confirm
Tracker.where(check_in_date: "2019-05-30")
.update_all("check_in_date = (#{
Application.select(:begin_date)
.where('applications.id = trackers.application_id').to_sql})"
)
The theory is that this should result in the following SQL
UPDATE trackers
SET check_in_date = (
SELECT
begin_date
FROM
applications
WHERE
applications.id = trackers.application_id
)
WHERE
trackers.check_in_date = "2019-05-30"
There seems some typo
if check_in_date is date type then convert is "2019-05-30" in date
my_check_in_date = "2019-05-30".to_date
While using any attribute in the query model name should always be plural
Tracker.joins(:application)
.where("trackers.check_in_date= ?", my_check_in_date)
.update_all("trackers.check_in_date = applications.begin_date")
.references(:application)

How do I count the number of records that have one or more associated object?

I have a Property model that has_many :photos. I want to count the number of properties that have one or more photo.
How do I do that?
I have tried the simple:
> Property.where('properties.photos.count > ?', 0).count
(3.1ms) SELECT COUNT(*) FROM "properties" WHERE (properties.photos.count > 1)
ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR: missing FROM-clause entry for table "photos"
LINE 1: SELECT COUNT(*) FROM "properties" WHERE (properties.photos....
^
: SELECT COUNT(*) FROM "properties" WHERE (properties.photos.count > 0)
from /ruby-2.3.0#myproject/gems/activerecord-3.2.22.5/lib/active_record/connection_adapters/postgresql_adapter.rb:1163:in `async_exec'
Caused by PG::UndefinedTable: ERROR: missing FROM-clause entry for table "photos"
LINE 1: SELECT COUNT(*) FROM "properties" WHERE (properties.photos....
to:
> Property.joins(:photos).where('photos.count > ?', 0).count
(3.7ms) SELECT COUNT(*) FROM "properties" INNER JOIN "photos" ON "photos"."property_id" = "properties"."id" WHERE (photos.count > 0)
ActiveRecord::StatementInvalid: PG::GroupingError: ERROR: aggregate functions are not allowed in WHERE
LINE 1: ..."photos"."property_id" = "properties"."id" WHERE (photos.cou...
^
: SELECT COUNT(*) FROM "properties" INNER JOIN "photos" ON "photos"."property_id" = "properties"."id" WHERE (photos.count > 0)
from ruby-2.3.0#myproject/gems/activerecord-3.2.22.5/lib/active_record/connection_adapters/postgresql_adapter.rb:1163:in `async_exec'
Caused by PG::GroupingError: ERROR: aggregate functions are not allowed in WHERE
LINE 1: ..."photos"."property_id" = "properties"."id" WHERE (photos.cou...
to the more advanced:
>Property.includes(:photos).group(['property.id', 'photos.id']).order('COUNT(photos.id) DESC').count
(0.6ms) SELECT COUNT(DISTINCT "properties"."id") AS count_id, property.id AS property_id, photos.id AS photos_id FROM "properties" LEFT OUTER JOIN "photos" ON "photos"."property_id" = "properties"."id" GROUP BY property.id, photos.id ORDER BY COUNT(photos.id) DESC
ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR: missing FROM-clause entry for table "property"
LINE 1: ...CT COUNT(DISTINCT "properties"."id") AS count_id, property.i...
^
: SELECT COUNT(DISTINCT "properties"."id") AS count_id, property.id AS property_id, photos.id AS photos_id FROM "properties" LEFT OUTER JOIN "photos" ON "photos"."property_id" = "properties"."id" GROUP BY property.id, photos.id ORDER BY COUNT(photos.id) DESC
from ruby-2.3.0#myproject/gems/activerecord-3.2.22.5/lib/active_record/connection_adapters/postgresql_adapter.rb:1163:in `async_exec'
Caused by PG::UndefinedTable: ERROR: missing FROM-clause entry for table "property"
LINE 1: ...CT COUNT(DISTINCT "properties"."id") AS count_id, property.i...
and a few other variations, and they all produce similar errors.
What am I doing wrong?
Note: All I want is the count of properties that have photos.count > 0. I don't want a hash of all the properties and the count of photos. In other words, if there are 5000 properties in my db, I want to build a scope that returns just the properties that actually have photos.
Since all you want is the Propertys with Photos then an INNER JOIN is all you need.
Property.joins(:photos)
That is it. If you want a scope then
class Property < ActiveRecord::Base
scope :with_photos, -> {joins(:photos)}
end
To get the count using rails 3.2
Property.with_photos.count(distinct: true)
You could also use: in rails 3.2
Property.count(joins: :photos, distinct: true)
ActiveRecord::Calculations#count Doc
This will execute
SELECT
COUNT(DISTINCT properties.id)
FROM
properties
INNER JOIN photos ON photos.property_id = properties.id
EDIT:
Property.joins(:photos).group('photos.property_id').having('count(photos.property_id) > 1').count
#=> {1234=>2} # 1234 is property id 2 is count of photos
You will get the property_ids with the number of associated photos with it.
Old Answer:
You can get the properties with atleast one photos associated with it
Property.includes(:photos).where.not(photos: { property_id: nil })
As you are using rails 3.2 .not will not work you have to use
Property.includes(:photos).where("property_id IS NOT null")
Property.includes(:photos).where("SELECT count(photos.id) > 0 FROM photos WHERE property_id = properties.id")
As a scope:
scope :with_photos, -> { where("SELECT count(photos.id) > 0 FROM photos WHERE property_id = properties.id") }
You can try like this, I have done in my projects,
Photo.group(:property_id).count
You will get property id with photos count
results = { 3314=>3, 2033=>3, 3532=>2, 3565=>6, 3510=>1, 3022=>7, 648=>2, 570=>3, 4678=>3, 3540=>1, 3489=>4, 536=>1, 1715=>4 }
Give this a go:
class Property < ApplicationRecord
has_many :photos
def self.with_photos
self.all.reject { |p| p.photos.empty? }
end
end
Property.with_photos.count
Source
More Efficient (Rails 4+):
Property.joins(:photos).uniq.count
Source
More Efficient (Rails 5.1+):
Property.joins(:photos).distinct.count
Source
According to your requirement you can try this
1) A simple count of the number of properties that have 1 or more
photo
To just get the number of properties which have one or more photo you can do this
Property.joins(:photos).distinct.count
As we are not using group the distinct or uniq is necessary. distinct will return ActiveRecord_Relation and uniq will return Array.
2) I would like that set of properties returned so I can
create a scope of just those properties. Also, I do have lots of
properties with more than 1 photo.
To get all the property objects which have one or more than one photo you can use the same query:
Property.joins(:photos).distinct
or you can use the group_by clause:
Property.joins(:photos).group('properties.id')
The difference will be that when you will use size method on the group query it will return a hash with the property_id as key and number of photos on the property as value.
Performance Update:
If you always require the count of associated object and you want to fetch it efficiently you may use counter_cache like this:
class Photo < ApplicationRecord
belongs_to :property, counter_cache: true
end
class Property < ApplicationRecord
has_many :photos
end
And then you will have to add a column in the properties table named photos_count and Rails will automatically update the column each time a new photo record is added or a exisisting photo record is removed. And then you can also query directly:
Property.where('photos_count > ?', 1)
This is optional and you can do this if you are facing performance issues with the data fetch.

Active Record doesn't update collection when there is joins and includes in query

Hello I've a problem with my query.
There are my models below:
class Owner
has_many :busiensses
has_many :adverts
end
class Business
belongs_to :owner
end
class Advert
belongs_to :owner
end
When I make this query everything is okay and it returns right collection full of needed objects:
Owner.joins(:adverts).includes(:businesses)
.where(businesses: {owner_id: nil})
But when I add to query update it raises error
Owner.joins(:adverts).includes(:businesses)
.where(businesses: {owner_id: nil})
.update_all(status: 'sth')
Error:
ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR: missing FROM-clause entry for table "businesses"
Where is the problem? I bet this error from SQL and it raised when you forget add sth to FROM statement and that sth needed in further conditions, but where in AR i forgot to add it?
Owner.joins(:adverts)
.includes(:businesses)
.where(businesses: {owner_id: 1})
.update_all(name: "blaaaaa")
This statement translates into this query:
UPDATE "owners"
SET "name" = 'blaaaaa'
FROM "businesses" /* missed this */
WHERE "owners"."id" IN
(SELECT "owners"."id" FROM "owners"
INNER JOIN "adverts"
ON "adverts"."owner_id" = "owners"."id"
WHERE "businesses"."owner_id" = 1)
You miss the "FROM 'bussinesses'" which causes the error:
missing FROM-clause entry for table "businesses"
My solution is to use joins instead of using includes. It works fine in my machine.
Owner.joins(:adverts)
.joins(:businesses)
.where(businesses: {owner_id: 1})
.update_all(name: "blaaaaa")
=> 1

How to find Model where this field or that field is in a list of acceptable values

How can I find the relationships where the start node or the end node is in the list.
ids = ProcessingRun.last.nodes.pluck(:id)
#rels = Relationship.where(:end_node_id => ids) + Relationship.where(:start_node_id => ids)
I've tried lots of variations on OR
rels_in_id_array = Relationship.where("start_node_id in #{ids} OR end_node_id in#{ids}")
Relationship Load (0.9ms) SELECT "relationships".* FROM "relationships" WHERE (start_node_id in [35752, 35726, 35728, 35729, 35731, 35735, 35736, 35738, 35742, 35745, 35750, 35751, 35723, 35725, 35739, 35740, 35749, 35724, 35722, 35733, 35734, 35737, 35741, 35743, 35732, 35746, 35747, 35721, 35730, 35727, 35744, 35748, 35753] OR end_node_id in[35752, 35726, 35728, 35729, 35731, 35735, 35736, 35738, 35742, 35745, 35750, 35751, 35723, 35725, 35739, 35740, 35749, 35724, 35722, 35733, 35734, 35737, 35741, 35743, 35732, 35746, 35747, 35721, 35730, 35727, 35744, 35748, 35753])
PG::SyntaxError: ERROR: syntax error at or near "["
LINE 1: ...".* FROM "relationships" WHERE (start_node_id in [35752, 35...
and it's not working....
so that's why I thought I'd add 2 arrays together. But it turns out they are arrays, not ActiveRecord relations, so I can't do things with them that you can do with AR relations.
Relationship.where("start_node_id IN (?) OR end_node_id IN (?)", ids, ids)
Relationship.where('end_node_id IN (?) OR start_node_id IN (?)', ids, ids)

count with has_many in rails

I've got an Order and Orderdetails
Orderdetails belongs_to Order
Order has_many Orderdetails
I am trying to convert the following query to ActiveRecord count function
select Count(*)
from orderdetails A, orders B
where A.prodid='6' and A.orderid= B.id and B.custid='11'
I tried:
#count = Orderdetail.count(:conditions => "prodid = 6 and order.custid = 11")
However, this gives error:
PGError: ERROR: syntax error at or near "order"
LINE 1: ...unt_all FROM "orderdetails" WHERE (prodid = 6 and order.cust...
Edit
I changed to orders
but now i get this error:
ActiveRecord::StatementInvalid:
PGError: ERROR: missing FROM-clause
entry for table "orders" LINE 1:
...unt_all FROM "orderdetails" WHERE
(prodid = 6 and orders.cus...
You need to add :joins => :order', because your condition contains element from orders table (that's why you get error missing FROM-clause), try:
#count = Orderdetail.count(:joins => :order, :conditions => "prodid = 6 and orders.custid = 11")
Also it better (safer) to use array in conditions:
#count = Orderdetail.count(:joins => :order, :conditions => ["prodid = ? and orders.custid = ?", 6, 11])
I think you should thoroughly read some docs on how associations work in rails. Try this guide.
You don't need to write any SQL in :conditions to do what you need.

Resources