Active record query with includes does not include - ruby-on-rails

I have got this 'query'
#product_collections = ProductCollection.
#includes(:products). #does not do anything
joins(:products). #this at least gives me the products (in articles table)
group("tags.id").
where("articles.category_id = ?", #category.id).
where("articles.available = ?", true).
order('tags.name asc')
this produces the following sql
SELECT "tags".* FROM "tags"
INNER JOIN "article_taggings" ON "tags"."id" = "article_taggings"."tag_id"
INNER JOIN "articles" ON "articles"."id" = "article_taggings"."article_id"
WHERE ("tags"."type" = 'ProductCollection')
AND (articles.category_id = 1)
AND (articles.available = 't')
GROUP BY tags.id
ORDER BY tags.name asc
how could I manage to get the products in one (or only one second) go?
Models:
class Article < ActiveRecord::Base
has_many :article_taggings
has_many :tags, :through => :article_taggings
end
class Product < Article
belongs_to :category
has_many :product_collections, :through => :article_taggings, :source => :tag
end
class ArticleTagging < ActiveRecord::Base
belongs_to :article
belongs_to :tag
end
class Tag < ActiveRecord::Base
has_many :article_taggings
has_many :articles, :through => :article_taggings
has_and_belongs_to_many :web_pages
end
class ProductCollection < Tag
has_many :products, :through => :article_taggings, :source => :article
end

You need to put the includes after joins. That will solve the problem.

Related

Counter_culture for has_one relationship (rails)

I use counter_culture gem, but when I want to use it, it throws an error that it cannot find product_id field in Product model, which makes sense because it should look for 'id'.
Below is the query generated when I call 'Product.counter_culture_fix_counts'. As you can see, it produced 'LEFT JOIN products AS products ON product_categories.id = products.product_id', which is not correct and it should be 'LEFT JOIN products AS products ON product_categories.product_id = products.id'.
SELECT categories.id, categories.id, COUNT(products.id) AS count, categories.products_count FROM "categories" LEFT JOIN product_categories AS product_categories ON categories.id = product_categories.category_id LEFT JOIN products AS products ON product_categories.id = products.product_id AND (products.active = 't') GROUP BY "categories"."id" ORDER BY "categories"."id" ASC LIMIT 1000 OFFSET 0
And here are the models:
# Product Model
class Product
has_one :product_category, dependent: :destroy
has_one :category, :through => :product_category
counter_culture [:product_category, :category], :column_name => Proc.new { |product| 'products_count' }, :column_names => { ["products.active = ?", true] => 'products_count' }, :touch => true
end
# ProductCategory Model
class ProductCategory
belongs_to :product
belongs_to :category
end
# Category Model
class Category
has_many :product_categories, dependent: :destroy
has_many :products, :through => :product_categories
end
Any idea how to get this working?
Thank you, Miro

has_many through association sql error

So, I'm trying to test my models associations with the following test:
it 'retrieve items registered under person' do
p = FactoryGirl.create(:person)
o = FactoryGirl.create(:order, customer: p)
o.customer.should == p
i = FactoryGirl.create(:item)
o.items << i
o.save
p.items.count.should == 1
end
My models:
class Person < AR:Base
has_many :orders, :as => :customer
has_many :items, :through => :orders
end
class Order < AR:Base
has_many :items
belongs_to :customer, :class_name => Person
end
class Item < AR:Base
belongs_to :order
has_one :customer, :class_name => Person, :through => :order
end
But when I run the test it gives me the following error:
SQLite3::SQLException: no such column: orders.customer_type: SELECT COUNT(*) FROM "items" INNER JOIN "orders" ON "items"."order_id" = "orders"."id" WHERE "orders"."customer_id" = 1 AND "orders"."customer_type" = 'Person'
What am I doing wrong?
Update:
The problem was on the ':as => :customer' bit. But my real problem was with the test. I should have assigned an order in the creation of an item.
It's because the :as option specifies a polymorphic interface. This explains "orders"."customer_type" = 'Person' in the where clause. I think what you mean to do is:
class Person < ActiveRecord::Base
has_many :orders, :foreign_key => :customer_id
has_many :items, :through => :orders
end
See the :as option in the guide.
I think Item should belong_to customer through order
class Item < AR:Base
belongs_to :order
belongs_to :customer, :class_name => Person, :through => :order
end

How do I setup a has_many relationship through another model but require uniqueness?

I have 4 models: Products, Vendors, Categories, CategoryProducts (join model).
A vendor has many products.
A product belongs_to a vendor.
A product has many categories.
A vendor has many categories through products.
This is how my models are setup now:
Vendor.rb
class Vendor < ActiveRecord::Base
attr_accessible :name, :description, :category_ids, :product_ids, :user_id
has_many :products, :dependent => :destroy
has_many :categories, :through => :products
belongs_to :owner, :class_name => "User",
:foreign_key => "user_id"
end
Product.rb
class Product < ActiveRecord::Base
attr_accessible :name, :description, :price, :vendor_id, :category_ids
belongs_to :vendor
has_many :category_products do
def with_categories
includes(:category)
end
end
has_many :categories, :through => :category_products
end
Category.rb
class Category < ActiveRecord::Base
attr_accessible :name, :product_ids, :category_ids
has_many :category_products do
def with_products
includes(:product)
end
end
has_many :products, :through => :category_products
end
The join model for Product & Category:
CategoryProduct.rb
class CategoryProduct < ActiveRecord::Base
attr_accessible :product_id, :category_id, :purchases_count
belongs_to :product
belongs_to :category
validates_uniqueness_of :product_id, :scope => :category_id
end
When I try to get the categories of a vendor on my command-line, it returns a lot of duplicate results - largely because it is essentially returning the category for each product owned by that vendor.
Here is an example, where v = Vendor.first:
1.9.3p194 :008 > v.products.count
(0.3ms) SELECT COUNT(*) FROM "products" WHERE "products"."vendor_id" = 10
=> 8
1.9.3p194 :009 > v.categories.count
(0.3ms) SELECT COUNT(*) FROM "categories" INNER JOIN "category_products" ON "categories"."id" = "category_products"."category_id" INNER JOIN "products" ON "category_products"."product_id" = "products"."id" WHERE "products"."vendor_id" = 10
=> 13
1.9.3p194 :010 > Category.count
(7.8ms) SELECT COUNT(*) FROM "categories"
=> 2
Some products have multiple categories, that's why there is a discrepancy between v.products.count and v.categories.count.
How do I get v.categories.count to just show me the unique amount of categories (in this case, the max is 2)?
Thanks.
I think it is fairly simple. Just use the uniq method as follows.
v.categories.uniq.count
To put it at association level you can use :uniq => true option as follows.
has_many :categories, :uniq => true

rails has_many_through creates a double join, how to optimize?

I have a situation in which Schools and EventLeg records are tied together through Photos, which belong to a given Event.
class Photo < ActiveRecord::Base
belongs_to :event
belongs_to :event_leg
has_and_belongs_to_many :schools
end
class Event < ActiveRecord::Base
has_many :event_legs, :through => :photos, :group => 'event_legs.id'
has_many :photos
end
class School < ActiveRecord::Base
has_and_belongs_to_many :photos
has_many :events, :through => :photos
has_many :event_legs, :through => :photos
end
class EventLeg < ActiveRecord::Base
has_many :photos
has_many :schools, :through => :photos
end
I need to get the schools that appeared in a given event leg at an event.
#event = Event.find 4088
#event.schools.joins(:photos).where('photos.event_leg_id' => 28034)
This results in SQL that joins the photos_schools table twice, once to schools and once to photos:
SELECT DISTINCT `schools`.* FROM `schools`
INNER JOIN `photos_schools` `photos_schools_join` ON `photos_schools_join`.`school_id` = `schools`.`id`
INNER JOIN `photos` `photos_schools_2` ON `photos_schools_2`.`id` = `photos_schools_join`.`photo_id`
INNER JOIN `photos_schools` ON `schools`.`id` = `photos_schools`.`school_id`
INNER JOIN `photos` ON `photos_schools`.`photo_id` = `photos`.`id`
WHERE `photos`.`event_id` = 4088 AND `photos`.`event_leg_id` = 28034
The second JOIN of photos_schools -> photos is unnecessary, the following query does the same thing and faster:
SELECT DISTINCT `schools`.* FROM `schools`
INNER JOIN `photos_schools` ON `schools`.`id` = `photos_schools`.`school_id`
INNER JOIN `photos` ON `photos_schools`.`photo_id` = `photos`.`id`
WHERE `photos`.`event_id` = 4088 AND photos.event_leg_id = 28034;
So why is AR creating this second set of joins, and how can I make it stop?
try skipping the joins(:photos) i guess it should work
#event.schools.where('photos.event_leg_id' => 28034)

How can I create a join without sql code in rails?

I can't make a join in rails, I don't know what is wrong here. my classes are:
class Serie < ActiveRecord::Base
has_many :user_serie
has_many :user, :through => :user_serie
end
class UserSerie < ActiveRecord::Base
belongs_to :serie
belongs_to :user
end
and
class User < ActiveRecord::Base
has_many :user_serie
has_many :serie, :through => :user_serie
end
and the select is:
#series = Serie.all :joins => :user
so the generated select is:
SELECT "series".* FROM "series"
INNER JOIN "user_series" ON "series"."id" = "user_series"."serie_id"
INNER JOIN "users"
ON 0
AND "users"
AND 'id'
AND "users"."id"
AND 0
AND "user_series"
AND 'user_id'
AND "user_series"."user_id"
AND "users"."id" = "user_series"."user_id"
What can I do to make this select works?
I've tried to make the has_many with plural, but then I have this error:
uninitialized constant Serie::UserSeries
You have wrong relations, should be:
class Serie < ActiveRecord::Base
has_many :user_series
has_many :users, :through => :user_series
end
class UserSerie < ActiveRecord::Base
belongs_to :serie
belongs_to :user
end
class User < ActiveRecord::Base
has_many :user_series
has_many :series, :through => :user_series
end
When you get exception with uninitialized class, then use explicit :class_name like below:
class Serie < ActiveRecord::Base
has_many :user_series, :class_name => "UserSerie"
# or "::UserSerie", i'm not 100% sure which one, rather just as I wrote
has_many :users, :through => :user_series
end

Resources