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
Related
I have the following models:
class Product < ActiveRecord::Base
has_many :product_recommendation_sets, :dependent => :destroy
has_many :recommendation_sets, :through => :product_recommendation_sets
end
class ProductRecommendationSet < ActiveRecord::Base
belongs_to :product
belongs_to :recommendation_set
end
class RecommendationSet < ActiveRecord::Base
has_many :product_recommendation_sets, :dependent => :destroy
has_many :products, :through => :product_recommendation_sets
has_many :recommendation_recommendation_sets, :dependent => :destroy
has_many :recommendations, :through => :recommendation_recommendation_sets
end
class RecommendationRecommendationSet < ActiveRecord::Base
belongs_to :recommendation
belongs_to :recommendation_set
end
class Recommendation < ActiveRecord::Base
has_many :recommendation_recommendation_sets, :dependent => :destroy
has_many :recommendations, :through => :recommendation_recommendation_sets
end
Im trying to select all recommendations where product_id = x, by doing:
RecommendationSet.joins(:products, :recommendations).where(product_id:1)
However I get an unknown column error. How can I join select all recommendations by a given product_id.
Psudo code:
Find recommendation_sets where product_id = ?. Find recommendations where recommendation_set_id = ?.
You were pretty close, in your case this should work:
RecommendationSet.joins(:products, :recommendations).where(products: { id: 1 })
Remember that in the where clause you have to use the table's name in the conditons hash, not the relation's name.
As an Example, consider these relations:
User belongs_to :group
Group has_many :users
Notice the syntax (plural / singular):
User.joins(:group).where(groups: { name: 'Admin' })
# ^ ^
Group.joins(:users).where(users: { id: 15 })
# ^ ^
I've read multiple questions about this, but have yet to find an answer that works for my situation.
I have 3 models: Apps, AppsGenres and Genres
Here are the pertinent fields from each of those:
Apps
application_id
AppsGenres
genre_id
application_id
Genres
genre_id
The key here is that I'm not using the id field from those models.
I need to associate the tables based on those application_id and genre_id fields.
Here's what I've currently got, but it's not getting me the query I need:
class Genre < ActiveRecord::Base
has_many :apps_genres, :primary_key => :application_id, :foreign_key => :application_id
has_many :apps, :through => :apps_genres
end
class AppsGenre < ActiveRecord::Base
belongs_to :app, :foreign_key => :application_id
belongs_to :genre, :foreign_key => :application_id, :primary_key => :application_id
end
class App < ActiveRecord::Base
has_many :apps_genres, :foreign_key => :application_id, :primary_key => :application_id
has_many :genres, :through => :apps_genres
end
For reference, here is the query I ultimately need:
#apps = Genre.find_by_genre_id(6000).apps
SELECT "apps".* FROM "apps"
INNER JOIN "apps_genres"
ON "apps"."application_id" = "apps_genres"."application_id"
WHERE "apps_genres"."genre_id" = 6000
UPDATED Try this:
class App < ActiveRecord::Base
has_many :apps_genres, :foreign_key => :application_id
has_many :genres, :through => :apps_genres
end
class AppsGenre < ActiveRecord::Base
belongs_to :genre, :foreign_key => :genre_id, :primary_key => :genre_id
belongs_to :app, :foreign_key => :application_id, :primary_key => :application_id
end
class Genre < ActiveRecord::Base
has_many :apps_genres, :foreign_key => :genre_id
has_many :apps, :through => :apps_genres
end
With query:
App.find(1).genres
It generates:
SELECT `genres`.* FROM `genres` INNER JOIN `apps_genres` ON `genres`.`genre_id` = `apps_genres`.`genre_id` WHERE `apps_genres`.`application_id` = 1
And query:
Genre.find(1).apps
generates:
SELECT `apps`.* FROM `apps` INNER JOIN `apps_genres` ON `apps`.`application_id` = `apps_genres`.`application_id` WHERE `apps_genres`.`genre_id` = 1
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
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.
I want to (as an example) create a has_many association to all posts by friends of a person, something like has_many :remote_posts to give me something like person > friends > person > posts.
..here is how I would go about it
script/generate model post title:string person_id:integer
script/generate model friendship person_id:integer friend_id:integer
script/generate model person name:string
class Person < ActiveRecord::Base
has_many :posts
has_many :friendships, :foreign_key => 'friend_id'
has_many :people, :through => :friendships
has_many :remote_posts, :class_name => 'Post', :through => :people, :source => :posts
end
class Friendship < ActiveRecord::Base
belongs_to :person
#also has a 'friend_id' to see who the friendship is aimed at
end
class Post < ActiveRecord::Base
belongs_to :person
end
# generate some people and friends
{'frank' => ['bob','phil'], 'bob' => ['phil']}.each {|k,v|
v.each {|f|
Friendship.create(
:person_id => Person.find_or_create_by_name(f).id,
:friend_id => Person.find_or_create_by_name(k).id
)
}
}
# generate some posts
Person.all.each {|p|
p.posts.create({:title => "Post by #{p.name}"})
}
Now,
Person.first.friendships # ..works
Person.first.people # (friends) ..works
Person.first.posts # ..works
Person.first.remote_posts #....
...and I get this error..
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: people.person_id: SELECT "posts".* FROM "posts" INNER JOIN "people" ON "posts".person_id = "people".id WHERE (("people".person_id = 1))
Aside from the foreign key error - seems like the friendships association isn't coming into play at all. I was thinking that this might be because of the :source => :posts, since the posts association would come into it twice.
I could write some finder sql (and that is what I have working at the moment), though I'd sooner do it this way.
Any ideas of how to get this to work?
How about this:
In the FriendShip class, add:
has_many :posts, :through => :person
and in the Person class, change the remote_posts to:
has_many :remote_posts, :class_name => 'Post',
:through => :friendships, :source => :person
How about a nested has_many :through relationship. This seems to work for me:
class Friendship < ActiveRecord::Base
belongs_to :person
belongs_to :friend, :class_name => 'Person'
has_many :posts, :through => :friend, :source => :posts
end
class Person < ActiveRecord::Base
has_many :posts
has_many :friendships, :foreign_key => 'friend_id'
has_many :people, :through => :friendships
has_many :remote_posts, :through => :friendships, :source => :posts
end
Note: this requires this nested_has_many_through plugin. (Note: direct linking to github repos seems to be broken... but that repo is there despite the error message.)