In my Rails 4 app, I have the following models:
User
has_many :administrations
has_many :calendars, through: :administrations
has_many :comments
has_many :calendar_comments, through: :calendars, :source => :comments
Calendar
has_many :administrations
has_many :users, through: :administrations
has_many :posts
has_many :comments, through: posts
has_many :ads
Administration
belongs_to :user
belongs_to :calendar
Post
belongs_to :calendar
has_many :comments, as: :commentable
Ad
belongs_to :calendar
has_many :comments, as: :commentable
Comment
belongs_to :commentable, polymorphic: true
belongs_to :user
I need to access the comments that belong_to an ad from the calendar the ad belongs_to.
This is what I am trying to do in my Calendars#Index action:
#posts_comments = #user.calendar_comments.where(commentable_type: "Post").order("created_at DESC").limit(5)
#ads_comments = #user.calendar_comments.where(commentable_type: "Ad").order("created_at DESC").limit(5)
My first guess was to add has_many :comments, through: ads in the Calendar model:
Calendar
has_many :administrations
has_many :users, through: :administrations
has_many :posts
has_many :comments, through: posts
has_many : ads
has_many :comments, through: ads
But that cancels the effect of has_many :comments, through: posts and then I can no longer access the comments that belong_to an post from the calendar the post belongs_to.
Is there a way to make BOTH has_many :comments, through: posts AND has_many :comments, through: ads work?
—————
UPDATE: according to this article and that Stack Overflow question, the answer may lay in the use of source: and source_type:.
Not sure how to use those however.
—————
UPDATE 2: would the following code make any sense?
class Calendar < ActiveRecord::Base
has_many :administrations, dependent: :destroy
has_many :users, through: :administrations
has_many :posts, dependent: :destroy
has_many :commented_posts, through: :comments, source: :commentable, source_type: 'Post'
has_many :ads, dependent: :destroy
has_many :commented_ads, through: :comments, source: :commentable, source_type: 'Ad'
—————
UPDATE 3: when I try the above code, I get the following error message:
Could not find the source association(s) :comments in model Calendar. Try 'has_many :calendar_comments, :through => :calendars, :source => <name>'. Is it one of administrations, users, posts, commented_posts, ads, commented_ads, invites, or pokes?
I tried the following:
class Calendar < ActiveRecord::Base
has_many :administrations, dependent: :destroy
has_many :users, through: :administrations
has_many :posts, dependent: :destroy
has_many :calendar_comments, :through => :calendars, :source => :post
has_many :ads, dependent: :destroy
has_many :calendar_comments, :through => :calendars, :source => :ad
—————
UPDATE 4: a new failed attempt with the following code:
class Calendar < ActiveRecord::Base
has_many :administrations, dependent: :destroy
has_many :users, through: :administrations
has_many :posts, dependent: :destroy
has_many :calendar_comments, :through => :commentable, :source => :post
has_many :ads, dependent: :destroy
has_many :calendar_comments, :through => :commentable, :source => :ad
Still not working, same error message as above.
—————
UPDATE 5: based on MrYoshiji's answer, I now have
class Calendar < ActiveRecord::Base
has_many :administrations, dependent: :destroy
has_many :users, through: :administrations
has_many :posts, dependent: :destroy
has_many :posts_comments, through: :posts, source_type: 'Post'
has_many :ads, dependent: :destroy
has_many :ads_comments, through: :ads, source_type: 'Ad'
Now, has_many :calendar_comments, through: :calendars, :source => :comments in the User model is no longer working.
I tried:
has_many :comments
has_many :calendar_post_comments, through: :calendars, :source => :post_comments
has_many :calendar_ad_comments, through: :calendars, :source => :ad_comments
Still not working.
—————
UPDATE 6: I am still stuck with this issue, since I cannot figure out a way to get the following code working:
#posts_comments = #user.calendar_comments.where(commentable_type: "Post").order("created_at DESC").limit(5)
#ads_comments = #user.calendar_comments.where(commentable_type: "Ad").order("created_at DESC").limit(5)
I tried many different things, and the best I could come up with so far was:
class Calendar < ActiveRecord::Base
has_many :administrations, dependent: :destroy
has_many :users, through: :administrations
has_many :posts, dependent: :destroy
has_many :post_comments, through: :posts, source_type: 'Post'
has_many :ads, dependent: :destroy
has_many :ad_comments, through: :ads, source_type: 'Ad'
end
class User < ActiveRecord::Base
has_many :administrations, dependent: :destroy
has_many :calendars, through: :administrations
has_many :comments
has_many :calendar_post_comments, through: :calendars, :source => :post_comments
has_many :calendar_ad_comments, through: :calendars, :source => :ad_comments
end
Then, I update my Calendars controller as follows:
def index
#user = current_user
#calendars = #user.calendars.all
#posts_comments = #user.calendar_post_comments
.order("created_at DESC")
.limit(5)
#ads_comments = #user.calendar_ad.comments
.order("created_at DESC")
.limit(5)
end
But this returns the following error:
NoMethodError at /calendars
undefined method `chain' for nil:NilClass
#posts_comments = #user.calendar_post_comments.order("created_at DESC").limit(5)
What is wrong here?
You should try the following:
class Calendar < ActiveRecord::Base
# [ ... ]
has_many :posts
has_many :posts_comments, through: posts, source_type: 'Post'
has_many :ads
has_many :ads_comments, through: ads, source_type: 'Ad'
Considering that Ad and Post models both have the following:
has_many :comments, as: :commentable
Related
I have a problem joining two models in a n..n association.
I have the following associations in the context:
Proposal n..n Product
Proposal n..n Project
Proposal n..n NewProject
And similarly with this, I have:
Order n..n Product
Order n..n Project
Order n..n NewProject
Well, the join model has the same attributes on both cases, but the partial for each of them is different.
Is there a way to do a single join model (Item), that would store all the data, and yet usable with the three different alias in Order and Proposal?
I tried to code it like this, but didn't work..
proposal.rb
class Proposal < ActiveRecord::Base
...
has_many :items
has_many :products, through: :items, source: :requisition, source_type: "Produto"
has_many :projects, through: :items, source: :requisition, source_type: "Projeto"
has_many :projects, through: :items, source: :requisition, source_type: "Novo"
...
end
order.rb
class Order < ActiveRecord::Base
...
has_many :items, as: :requisition, dependent: :destroy
has_many :products, through: :items, source: :requisition, source_type: "Produtos"
has_many :projects, through: :items, source: :requisition, source_type: "Projetos"
has_many :projects, through: :items, source: :requisition, source_type: "Novos"
...
end
product.rb
class Product < ActiveRecord::Base
has_many :items, as: :piece, dependent: :destroy
has_many :orders, through: :items, source: :piece, source_type: 'Order'
has_many :proposals, through: :items, source: :piece, source_type: 'Proposal'
...
end
project.rb
class Project < ActiveRecord::Base
has_many :items, as: :piece, dependent: :destroy
has_many :orders, through: :items, source: :piece, source_type: 'Order'
has_many :proposals, through: :items, source: :piece, source_type: 'Proposal'
...
end
item.rb
class Item < ApplicationRecord
belongs_to :piece, polymorphic: true
belongs_to :requisition, polymorphic: true
...
end
I expect to unify this associations, to clear some tables, and try to speed up the app.
I have been experiencing problems when trying to destroy_all my users in my database. When I run User.destroy_all I get:
ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection: Cannot modify association 'Account#hotel_partnerships' because the source reflection class 'Partnership' is associated to 'Hotel' via :has_many.
I suspect that the main problem is that in my schema I have an accountmodel that belongs_to a user(the owner of the account) and at the same time the account has_many users through its offices and hotels.
Here's how my associations look like :
- Account.rb
class Account < ActiveRecord::Base
# associations
has_many :hotel_partnerships, through: :hotels, source: :partnerships, dependent: :destroy
has_many :office_partnerships, through: :offices, source: :partnerships, dependent: :destroy
has_many :hotel_users, through: :hotels,source: :users, dependent: :destroy
has_many :office_users, through: :offices, source: :users, dependent: :destroy
has_many :hotels, dependent: :destroy
has_many :offices, dependent: :destroy
has_many :rooms, through: :hotels, dependent: :destroy
has_many :tasks, through: :hotels, dependent: :destroy
belongs_to :admin, class_name: "User", foreign_key: "admin_user_id", dependent: :destroy
- User.rb
class User < ActiveRecord::Base
## this line adds auth token to all user on creation
acts_as_token_authenticatable
# associations
belongs_to :account, dependent: :destroy
has_and_belongs_to_many :hotels
has_and_belongs_to_many :offices
has_many :tasks, dependent: :destroy
has_many :bookings, dependent: :destroy
has_one :created_account, class_name: "Account", foreign_key: "admin_user_id", inverse_of: :admin, dependent: :destroy
- Partnership.rb
class Partnership < ActiveRecord::Base
belongs_to :hotel
belongs_to :office
- Hotel.rb
class Hotel < ActiveRecord::Base
geocoded_by :full_address
after_validation :geocode
has_many :partnerships
belongs_to :account
has_and_belongs_to_many :users
has_many :tasks, dependent: :destroy
has_many :rooms, dependent: :destroy
has_many :beds, through: :rooms, dependent: :destroy
has_many :photos, dependent: :destroy
accepts_nested_attributes_for :photos
accepts_nested_attributes_for :rooms
Is it possible to fix this circular association problem ?
I'm trying to create way for Users to Like content in my project. To do this I set up a polymorphic relationship as follows
Likes table
table "likes", force: :cascade do |t|
t.integer "likeable_id"
t.string "likeable_type"
t.integer "user_id", null: false
t.datetime "created_at"
t.datetime "updated_at"
end
models
class User < ActiveRecord::Base
has_many :likes, dependent: :destroy
has_many :newsletters, through: :likes, source: :likeable, source_type: "newsletter"
has_many :gift_cards, through: :likes, source: :likeable, source_type: "gift_card"
has_many :stories, through: :likes, source: :likeable, source_type: "story"
end
class Like < ActiveRecord::Base
belongs_to :user
belongs_to :likeable, polymorphic: true
end
class Newsletter < ActiveRecord::Base
has_one :like, as: :likeable, dependent: :destroy
has_one :user, through: :like, source: :likeable
end
class GiftCard < ActiveRecord::Base
has_many :likes, as: :likeable, dependent: :destroy
has_many :users, through: :likes, source: :likeable
end
class Story < ActiveRecord::Base
has_many :likes, as: :likeable, dependent: :destroy
has_many :users, through: :likes, source: :likeable
end
tldr: a User has many Likes and many Newsletters, GiftCards, and Stories through those Likes.
My question, with this structure, whats the best way to get everything a User has liked?
For me this is extremely hard to follow for a domain with is in reality is quite straightforwards. Perhaps you have a bigger reason to implement it is this way but here's my suggestion for the User Like and GiftCard models (which may or may not help!).
class User < ActiveRecord::Base
has_many :likes, dependent: :destroy
has_many :liked_giftcards, through: :likes, source: :giftcard
end
class Like < ActiveRecord::Base
belongs_to :user
belongs_to :giftcard
end
class GiftCard < ActiveRecord::Base
has_many :likes, dependent: :destroy
end
class Story < ActiveRecord::Base
...same as GiftCard
end
Personally I would find this easier to follow. It provides easy access to everything a user has liked through user.likes and allows you to look at each category individually through user.liked_giftcards etc.
Ended up figuring it out. Just had some small syntactical errors
class User < ActiveRecord::Base
has_many :likes, dependent: :destroy
has_many :newsletters, through: :likes, source: :likeable, source_type: "Newsletter"
has_many :gift_cards, through: :likes, source: :likeable, source_type: "GiftCard"
has_many :stories, through: :likes, source: :likeable, source_type: "Story"
end
class Like < ActiveRecord::Base
belongs_to :user
belongs_to :likeable, polymorphic: true
end
class Newsletter < ActiveRecord::Base
has_one :like, as: :likeable, dependent: :destroy
has_one :user, through: :like
end
class GiftCard < ActiveRecord::Base
has_many :likes, as: :likeable, dependent: :destroy
has_many :users, through: :likes
end
class Story < ActiveRecord::Base
has_many :likes, as: :likeable, dependent: :destroy
has_many :users, through: :likes
end
I have four models:
User
Listing
Order
OrderGroup
User:
has_many :listings
has_many :orders
Listing:
belongs_to :seller, class_name: "User", foreign_key: :user_id
has_many :order_groups, through: :orders
has_many :orders
Order:
has_one :seller, through: :listing
belongs_to :listing
belongs_to :order_group
OrderGroup:
has_many :listings, through: :orders
has_many :orders
has_many :sellers, through: :orders
When I try to pull Order.where(seller: User.find(3)), I get an empty collection. However, when I do Order.last.seller, I get the seller's user_id.
How can I pull Order.where(seller: User.find(3))' ?
You can write query as
Order.joins(:listing).where('listings.user_id = ?', 3)
Models:
class User < ActiveRecord::Base
has_many :reports
has_many :social_accounts
has_one :api_client
has_many :integrations
has_many :profiles, through: :integrations
has_many :tags
has_many :profiles, through: :tags
end
class Tag < ActiveRecord::Base
belongs_to :user
belongs_to :profile
end
class Profile < ActiveRecord::Base
has_many :integration_profiles
has_many :integrations, through: :integration_profiles
has_many :users, through: :integrations
belongs_to :api_client
has_many :tags
ene
At times I want to retrieve all of the user's profiles through the integrations and other times through tags. How?
The answer:
has_many :profiles_tagged, through: :tags, source: :profile
On the User model