has_many through polymorphic with alias on both sides - ruby-on-rails

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.

Related

Remove association from Rails 5 self join table without deleting

I have a self join table on my product model using a model called matches as the join table. What I would like to do is when deleting a product to have the associated product removed but not deleted. Right now I am trying dependent: :destroy which doesn't work, but I know its not what I want because I don't want to delete the self associated product.
product.rb
class Product < ApplicationRecord
...
has_many :variations, -> { order(:order) }, dependent: :destroy
has_and_belongs_to_many :categories
has_and_belongs_to_many :tags
has_many :matches
has_many :matched_products, through: :matches, dependent: :destroy
...
end
match.rb
class Match < ActiveRecord::Base
belongs_to :product
belongs_to :matched_product, class_name: 'Product', dependent: :destroy
has_many :variations, :through => :matched_product
end
I suggest you update your models as follows:
product.rb
class Product < ApplicationRecord
...
has_many :variations, -> { order(:order) }, dependent: :destroy
has_and_belongs_to_many :categories
has_and_belongs_to_many :tags
has_many :matches, dependent: :destroy
has_many :product_matches, class_name: 'Match', foreign_key: :matched_product_id, dependent: :destroy
has_many :matched_products, through: :matches
...
end
This will ensure that all matches records are deleted when deleting a product whether the product is a product or matched_product in the match record. Removing dependent: :destroy from has_many :matched_products will prevent deletion of the, well, matched_products.
match.rb
class Match < ActiveRecord::Base
belongs_to :product
belongs_to :matched_product, class_name: 'Product'
has_many :variations, :through => :matched_product
end
Similar to above, removing dependent: :destroy from belongs_to :matched_product, class_name: 'Product' will prevent deletion of the matched_product.

How do target polymorphic model through many models

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.

ActiveRecord has many through with both being polymorphic

I have the association setup like the below, but I'm getting errors/exceptions thrown from Rails telling me that I don't have the associations set up properly.
Here's what I have:
class Case
has_many :case_accesses, as: :policy, inverse_of: :case, dependent: :destroy
has_many :agents, through: :case_accesses, source: :ownable, source_type: 'Agent'
end
class CaseAccess
belongs_to :policy, polymorphic: true
belongs_to :ownable, polymorphic: true
end
class Agent
has_many :case_accesses, as: :ownable, dependent: :destroy
has_many :cases, through: :case_accesses
end
The error from Rails:
Could not find the source association(s) "case" or :cases in model CaseAccess. Try 'has_many :cases, :through => :case_accesses, :source => '. Is it one of policy, connection, or ownable?
I tried setting the source to ownable and it's causing problems in my query. How should I be setting up this association? It's a traditional has many through, except on one side the policy can be either of type Case or Ppae, and the ownable can be of type Agent or User.
Columns for tables:
Case
-id
CaseAccess
-id
-policy_id
-policy_type
-ownable_id
-ownable_type
Agent
-id
A Case has many case_accesses as policy. Is the CaseAccess the policy, or is the Case the policy for the CaseAccess?
I believe you need to change
has_many :case_accesses, as: :policy, inverse_of: :case, dependent: :destroy
to
has_many :case_accesses, inverse_of: :policy, dependent: :destroy
This is what did it:
class Case
has_many :case_accesses, as: :policy, inverse_of: :policy, dependent: :destroy
has_many :agents, through: :case_accesses, source: :ownable, source_type: 'Agent'
has_many :users, through: :case_accesses, source: :ownable, source_type: 'User'
end
class CaseAccess
belongs_to :policy, polymorphic: true
belongs_to :ownable, polymorphic: true
end
class Agent
has_many :case_accesses, as: :ownable, dependent: :destroy
has_many :cases, through: :case_accesses, source: :policy, source_type: 'Case'
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

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

Resources