consider this code
class User < ActiveRecord::Base
has_many :views
has_many :posts, :through => :views, :uniq => true
has_many :favorites
has_many :posts, :through => :favorites, :uniq => true
has_many :votes
has_many :posts, :through => :votes, :uniq => true
end
# controller code
user = User.find(3)
posts = user.posts # ??
that said i have established three relationships between posts and users, through different way. But what about the last line??? how can I tell rails that I want to get the posts through views or favorites.
You can give each association a different name, but point it at the same model using the :class_name option. Like so:
class User < ActiveRecord::Base
has_many :views
has_many :view_posts, :through => :views, :class_name => 'Post', :uniq => true,
has_many :favorites
has_many :favorite_posts, :through => :favorites, :class_name => 'Post', :uniq => true
has_many :votes
has_many :vote_posts, :through => :votes, :class_name => 'Post', :uniq => true
end
# Then...
User.find(3).favorite_posts
You may also find named_scope useful.
You have to give the associations different names. The 2nd and 3rd has_many :posts just overwrite the previous ones. You will need something like has_many :view_posts, has_many :favorite_posts, etc.
Related
I'm having a problems with :group and :uniq tags as an option to has_many through collection definition. I have many triple model associations defined on my system and I want to list elements grouped to avoid (the actual) repetition. My main model looks like that:
class Trip < ActiveRecord::Base
belongs_to :agent
has_many :trips_destinations, :class_name => "TripsDestination"
has_many :destinations, :through => :trips_destinations
has_and_belongs_to_many :vibes, join_table: :trips_vibes
has_and_belongs_to_many :verbs, join_table: :trips_verbs
has_many :trips_destinations_activities, :class_name => "TripsDestinationsActivity"
has_many :activities, :through => :trips_destinations_activities, :uniq => true
has_many :trips_destinations_hotels, :class_name => "TripsDestinationsHotel"
has_many :hotels, :through => :trips_destinations_hotels
has_many :trips_destinations_recommended_places, :class_name => "TripsDestinationsRecommendedPlace"
has_many :recommended_places, :through => :trips_destinations_recommended_places
has_many :trips_destinations_transportations, :class_name => "TripsDestinationsTransportation"
has_many :transportations, :through => :trips_destinations_transportations
...
...
end
Anyone know how to list they why avoiding repetition given the pair [trip_id, destination_id]?
And why they are repeated?
My rails version is 4 and I the image below shows the error message when passing grouping options to has_many relation.
Please help!
Your syntax for uniq is not correct for Rails 4.
has_many :activities, -> { uniq }, :through => :trips_destinations_activities
Unique now has scope syntax.
I have two tables for tagging so that I can attach tags to any models, it works likes so…
There's a tagged item join table which has a tag_id column and then two other columns for polymorphism: taggable_type and taggable_id…
class TaggedItem < ActiveRecord::Base
attr_accessible :taggable_id, :taggable_type, :tag_id
belongs_to :taggable, :polymorphic => true
belongs_to :tag
end
There's also all of the things that can have tags, for example here's a product and image model with tags attached:
class Product < ActiveRecord::Base
has_many :tagged_items, :as => :taggable, :dependent => :destroy
has_many :tags, :through => :tagged_items
end
class Image < ActiveRecord::Base
has_many :tagged_items, :as => :taggable, :dependent => :destroy
has_many :tags, :through => :tagged_items
end
The problem is with the tag model, I can seem to get the reverse work, on the tag modle I want to have a has_many images and has_many products like so:
class Tag < ActiveRecord::Base
has_many :tagged_items, :dependent => :destroy
has_many :products, :through => :tagged_items
has_many :images, :through => :tagged_items
end
This is causing an error, I was wondering how I can fix this. So the tag table works through the polymorphic tagged items table.
Any help would be much appreciated. Thanks!
Edit:
Could not find the source association(s) :product or :products in model TaggedItem. Try 'has_many :products, :through => :tagged_items, :source => <name>'. Is it one of :taggable or :tag?
The has_many :through associations in your Tag model are not able to get the source association for Product and Image from the TaggedItem Model. e.g. has_many :products, :through => :tagged_items will look for a direct association belongs_to :product in TaggedItem which in case of polymorphic association is written as belongs_to :taggable, :polymorphic => true. So for the Tag model to understand exact source of the association we need to add an option :source and its type as :source_type
So change your Tag model associations to look like
class Tag < ActiveRecord::Base
has_many :tagged_items, :dependent => :destroy
has_many :products, :through => :tagged_items, :source => :taggable, :source_type => 'Product'
has_many :images, :through => :tagged_items, :source => :taggable, :source_type => 'Image'
end
This should fix your problem. :)
you do not need the as option when you set up the Tag association to TaggedItem. :as => :taggable would mean that tag on tagged item is polymorphic which it is not. Instead the other side is, ie., the items that are taggable as your name cleverly suggests :).
class Tag < ActiveRecord::Base
has_many :tagged_items, :dependent => :destroy
has_many :products, :through => :tagged_items
has_many :images, :through => :tagged_items
end
Let's assume I have an application with a "favorites" feature, where users can add a document, note, or comment to his favorites list.
In my mind..
User has_many Favorites
Favorite belongs_to a User
Document belongs_to a Favorite
Note belongs_to a Favorite
Comment belongs_to a Favorite
What's the problem with this type of association and how would polymorphic associations help?
because then your Favorite instance will not know what it is favouriting :)
it knows that it has_one :note, but also has_one :comment, or? but not both surely.
polymorphic association the opposite way helps because it will express that a Favorite object belongs_to :favorited object that is polymorphic cos it can be any class the name of which will be stored in the :favorited_type string db column, so your favorite object will know that it favors a note or document or comment.
with some code
class Note
has_many :favorites, :as => :favorited
has_many :fans, :through => :favorites, :source => :user
end
class Discussion
has_many :favorites, :as => :favorited
has_many :fans, :through => :favorites, :source => :user
end
class Comment
has_many :favorites, :as => :favorited
has_many :fans, :through => :favorites, :source => :user
end
class Favorite
belongs_to :user
belongs_to :favorited, :polymorphic => true # note direction of polymorphy
end
class User
has_many :favorites
has_many :favorite_notes, :through => :favorites, :source => favorited, :source_type => "Note"
has_many :favorite_comments, :through => :favorites, :source => favorited, :source_type => "Comment"
has_many :favorite_discussions, :through => :favorites, :source => favorited, :source_type => "Discussion"
end
(just set up your db correctly) this design is standard for such usecase of favoriting.
I have a Partner model that has_and_belongs_to_many Projects, while each Project has_many Sites. I want to retrieve all sites for a given partner (and am not interested in the projects in between at the moment).
I have accomplished what I need through a named_scope on the Site model, and a project.sites instance method that wraps a call to the Site named scope, as follows:
class Partner < ActiveRecord::Base
has_and_belongs_to_many :projects
def sites
Site.for_partner_id(self.id)
end
end
class Project < ActiveRecord::Base
has_many :sites
end
class Site < ActiveRecord::Base
belongs_to :project
named_scope :for_partner_id, lambda {|partner_id|
{ :include=>{:project=>:partners},
:conditions=>"partners.id = #{partner_id}"
}
}
end
Now, given a partner instance, I can call partner.sites and get back a collection of all sites associated with the partner. This is precisely the behavior I want, but I'm wondering if there's another way to do this using only activerecord associations, without the named scope?
I had a similar deep nesting query/collection problem here (I had to threaten to repeat data before anyone would answer my 4 questions, clever):
Is it appropriate to repeat data in models to satisfy using law of demeter in collections?
The trick is this gem http://rubygems.org/gems/nested_has_many_through which can do something like this:
class Author < User
has_many :posts
has_many :categories, :through => :posts, :uniq => true
has_many :similar_posts, :through => :categories, :source => :posts
has_many :similar_authors, :through => :similar_posts, :source => :author, :uniq => true
has_many :posts_of_similar_authors, :through => :similar_authors, :source => :posts, :uniq => true
has_many :commenters, :through => :posts, :uniq => true
end
class Post < ActiveRecord::Base
belongs_to :author
belongs_to :category
has_many :comments
has_many :commenters, :through => :comments, :source => :user, :uniq => true
end
This has super-simplified my queries and collections. I hope you find an answer to your problem, it's a tough one!
I have a User Model(:name, :password, :email), and Event model(:name, :etc) and Interest model (:name) [>all singular<]
Then I created two join tables -> UsersInterests and EventsInterests; each not containing a primary key and only comprised of the user_id/interest_id and event_id/interest_id respectively. [>plural<]
My Models Use the Nested Has Many Through Plugin
user.rb => has_many :users_interests
has_many :interests, :through => :users_interests
has_many :events_interests, :through => :interests
has_many :events, :through => :events_interests
event.rb => has_many :events_interests
has_many :interests, :through => :events_interests
has_many :users_interests, :through => :interests
has_many :users, :through => :users_interests
interest.rb => has_and_belongs_to_many :users
has_and_belongs_to_many :events
events_interests.rb => belongs_to :interests
belongs_to :events
users_interests.rb => belongs_to :users
belongs_to :interests
Whew..ok So I wanted to created a named_scope of that find all the events that share interest with a particular user. Here is some code someone helped me with.
named_scope :shares_interest_with_users, lambda {|user|
{ :joins => :users_interests,
:conditions => {:users_interests => {:user_id => user}}
}}
When i run from the controller =>
#user = User.find(1)
#events = Event.shares_interest_with_user(#user)
I get the error :
uninitialized constant Event::EventsInterest
Can anyone see what i messed up?
You must have named something wrong along the way. At a glance I'd say you have a file or class named incorrectly. Remember model names MUST always be singular, both in file and class names or else Rails won't make the connection. Another source of your problem is that arguments to belongs_to must also be singular. Even if you had got things right, the HABTM relationship in interests with users would have thrown an error when you ran the named scope.
I was able to solve your error with the following models.
user.rb
class User < ActiveRecord::Base
has_many :users_interests
has_many :interests, :through => :users_interests
has_many :events_interests, :through => :interests
has_many :events, :through => :events_interests
end
users_interest.rb
class UsersInterest < ActiveRecord::Base
belongs_to :user
belongs_to :interest
end
interest.rb
class Interest < ActiveRecord::Base
has_many :users,:through => :users_interests
has_many :users_interests
has_many :events_interests
has_many :events, :through => :events_interests
end
**events_interest.rb
class EventsInterest <ActiveRecord::Base
belongs_to :interest
belongs_to :event
end
event.rb
class Event <ActiveRecord::Base
has_many :events_interests
has_many :interests, :through => :events_interests
has_many :users_interests, :through => :interests
has_many :users, :through => :users_interests
named_scope :shares_interest_with_users, lambda {|user|
{ :joins => :users_interests,
:conditions => {:users_interests => {:user_id => user}}
}
}
end