How do target polymorphic model through many models - ruby-on-rails

I have 4 classes:
class User < ApplicationRecord
has_many :memories
has_many :playlists
has_many :items, as: 'playlist_items', through: :playlists
has_many :items, as: 'memory_items', through: :memories
end
class Item < ApplicationRecord
belongs_to :itemable, polymorphic: true, optional: true
end
class Playlist < ApplicationRecord
belongs_to :user
has_many :items, as: :itemable, dependent: :destroy
accepts_nested_attributes_for :items, allow_destroy: true
end
class Memory < ApplicationRecord
belongs_to :user
has_many :items, as: :itemable, dependent: :destroy
accepts_nested_attributes_for :items, allow_destroy: true
end
I would like to be able to get from current_user to the items of either type, i.e. Memory or Playlist. But right now I can only get to 1 set.. if I have this in User:
has_many :items, through: :playlists
I can't currently figure out how to do both in a list. 'As' seems to have no effect. Any suggestions would be very helpful?

You can't have both associations with the same name, you can specialize specifying the source. Try like this:
class User < ApplicationRecord
has_many :memories
has_many :playlists
has_many :playlist_items, through: :playlists, source: :items
has_many :memory_items, through: :memories, source: :items
end
Then of course you use user.playlist_items and user.memory_items instead.

Related

ActiveRecord grab shared model from polymorphic association

I'm looking for a better way to query Users from 2 different Models used in a polymorphic association. Here is the setup
class Schedule < ApplicationRecord
belongs_to :announcement
has_many :targets, dependent: :destroy
has_many :lists, through: :targets, source: :target, source_type: 'List'
has_many :accounts, through: :targets, source: :target, source_type: 'Account'
end
class Target < ApplicationRecord
# belongs_to :announcement
belongs_to :schedule
belongs_to :target, polymorphic: true
delegate :announcement, to: :schedule
end
class List < ApplicationRecord
belongs_to :account
has_many :targets, as: :target, dependent: :destroy
has_many :lists_users
has_many :users, through: :lists_users
end
class Account < ApplicationRecord
has_many :announcements, dependent: :destroy
has_many :targets, as: :target, dependent: :destroy
has_many :users, dependent: :destroy
end
At the moment I'm solving this by creating a method inside the Schedule model that grabs Users this way:
def subscribers
targets.map(&:target).map(&:users).flatten.uniq
end
I looked at something similar with this question, but didn't seem to solve it.
I would do that like this:
class Schedule < ApplicationRecord
def subscribers
# fetch all associated user IDs
lists_user_ids = lists.joins(:lists_users).distinct.pluck("lists_users.user_id")
accounts_user_ids = accounts.joins(:users).distinct.pluck("users.id")
user_ids = (lists_user_ids + accounts_user_ids).uniq
# fetch users by IDs
User.where(id: user_ids)
end
end

Get all related instances from has_many through relationship of a polymorphic class

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

has_many of the same table through several others

What am trying to do is:
i have a User model and i have a Task model
Task has 2 types of users Owners and Supervisors all of them are users !
so what i have so far is:
Task Model
class Task < ActiveRecord::Base
has_many :task_owners, dependent: :destroy
has_many :task_supervisors, dependent: :destroy
has_many :users, through: :task_owners
has_many :users, through: :task_supervisors
end
TaskSupervisor Model
class TaskSupervisor < ActiveRecord::Base
belongs_to :task
belongs_to :user
end
TaskOwner Model
class TaskOwner < ActiveRecord::Base
belongs_to :task
belongs_to :user
end
and finally the User Model
class User < ActiveRecord::Base
has_many :task_owners
has_many :task_supervisors
has_many :tasks, through: :task_owners
has_many :tasks, through: :task_supervisors
end
now as you can imagine ... my problem is when i get a task and retrieve the users i only get one of my associations ... what i need is a way to change the getters name or identify them some how basically to be able to say something like
task.owners
task.supervisors
class Task < ActiveRecord::Base
has_many :task_owners, dependent: :destroy
has_many :task_supervisors, dependent: :destroy
has_many :owners, through: :task_owners, source: :users
has_many :supervisors, through: :task_supervisors, source: :users
end
You should be able to do this.
Then you should get your task.owners and task.supervisors
Edit:
You will need to change your user model to
class User < ActiveRecord::Base
has_many :task_owners
has_many :task_supervisors
has_many :owned_tasks, through: :task_owners, source: :tasks
has_many :supervised_tasks, through: :task_supervisors, source: :tasks
end

Two has_many throughs to the same model Rails

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

has_many through polymorphic with custom type

I have 2 applications one that serves as an API and has read only access and one that is the primary application. In the primary app, I have a has many through polymorphic relationship. The models in the main app look like so, and they work great:
class Category < ActiveRecord::Base
has_many :category_associations
has_many :posts, through: :category_associations
has_many :pages, through: :category_associations
end
class Post < ActiveRecord::Base
has_many :category_associations, as: :associated
has_many :categories, as: associated, through: :category_associations, source: :post
end
class Page < ActiveRecord::Base
has_many :category_associations, as: :associated
has_many :categories, as: associated, through: :category_associations, source: :post
end
class CategoryAssociation
belongs_to :category
belongs_to :associated, polymorphic: true
end
Now for the second app I will need to access the same tables but my class names will be different, this effects the type field that I cannot seem to override even with source_type.:
class Category < ActiveRecord::Base
has_many :category_associations
has_many :articles, through: :category_associations
has_many :static_contents, through: :category_associations
end
class Article < ActiveRecord::Base
self.table_name = 'posts'
has_many :category_associations, as: :associated
has_many :categories, as: associated, through: :category_associations, source: :article, source_type: 'Post'
end
class StaticContent < ActiveRecord::Base
self.table_name = 'pages'
has_many :category_associations, as: :associated
has_many :categories, as: associated, through: :category_associations, source: :static_content, source_type: 'Page'
end
class CategoryAssociation
belongs_to :category
belongs_to :associated, polymorphic: true
end
I get the following Error:
=> Posts.first.categories
# ActiveRecord::HasManyThroughAssociationPointlessSourceTypeError: Cannot have a has_many :through association 'Post#categories' with a :source_type option if the 'CategoryAssociation#category' is not polymorphic. Try removing :source_type on your association.
It also seems that when I grab the posts from the category
Have you tried putting polymorphic:true to the category belongs_to? It seems that's the direction pointed by the error message points, though I'm not sure
class CategoryAssociation
belongs_to :category, polymorphic: true
...
end

Resources