Rails polymorphic comments associate - ruby-on-rails

Trying to work out an polymorphic association where Comments can belong to, for example, Photos and Users. Where a Comment on a user is treated as a "direct message". But I'm getting the User association a bit messed up.
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
end
class Photo < ActiveRecord::Base
has_many :comments, as: :commentable, dependent: :destroy
end
class User < ActiveRecord::Base
has_many :comments, dependent: :destroy
has_many :messages, as: :commentable
end
This is incorrect. Ideally, user.comments should retrieve all Comment records where user_id == user.id and something like user.messages should retrieve all Comments where the type is User and they are the subject.

Relationships:
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
belongs_to :user
end
class Photo < ActiveRecord::Base
has_many :comments, as: :commentable, dependent: :destroy
end
class User < ActiveRecord::Base
has_many :comments, dependent: :destroy
has_many :messages, as: :commentable, class_name: 'Comment'
end
Schema:
# Comments
...
t.integer :user_id
t.integer :commentable_id
t.string :commentable_type
...
Then you can invoke:
#user.comments # Get all comments created by particular user
#user.messages # Get all comments where particular user is a subject

have you added the foreign key and type columns to the comments table? within a migration file:
def change
add_column :comments, :commentable_type, :integer
add_column, :commentable_type, :string
add_index :comments, [:commentable_type, :commentable_id]
end
Also make sure you have a Message model and it has the associations
class Message < ActiveRecord::Base
has_many :comments, dependent: :destroy
belongs_to :commentable, polymorphic: true
end

Related

Create a relationship that allows a user to follow multiple types of records

I am currently working on a system that allows a user to follow different records (funds or wallets) but I am blocking on relationships.
I have three models: User, Fund and Wallet.
A user must be able to follow to multiple funds or wallets, and a fund or wallet must be able to have multiple followers.
The goal is to be able to do user.follows which would give me the list of records he follows (funds and wallets), and to do fund.followers or wallet.followers and get the list of users who follow these records.
I have created this table:
class CreateFollows < ActiveRecord::Migration[6.0]
def change
create_table :follows do |t|
t.integer :user_id
t.integer :followable_id
t.string :followable_type
t.timestamps
end
end
end
then I did:
class User < ApplicationRecord
has_many :follows, dependent: :destroy
end
class Follow < ApplicationRecord
belongs_to :follower, foreign_key: :user_id, class_name: 'User', inverse_of: :follows
belongs_to :followable, polymorphic: true
end
and this concern that I added to Fund and Wallet models:
module Followable
extend ActiveSupport::Concern
included do
has_many :followers, dependent: :destroy
end
end
I know it can't work as it is now, but I don't really understand what to put in the User model and in my concern. Can someone show me the path please?
I finally did the following:
class Follow < ApplicationRecord
belongs_to :follower, foreign_key: :user_id, class_name: 'User', inverse_of: :follows
belongs_to :followable, polymorphic: true
end
class User < ApplicationRecord
has_many :follows, dependent: :destroy
has_many :funds_followings, through: :follows, source: :followable, source_type: 'Fund'
has_many :wallets_followings, through: :follows, source: :followable, source_type: 'Wallet'
def followings
funds_followings + wallets_followings
end
end
module Followable
extend ActiveSupport::Concern
included do
has_many :follows, foreign_key: :followable_id, dependent: :destroy, inverse_of: :followable
has_many :followers, through: :follows, as: :followable
end
end
So I'm able to do everything I wanted.

Rails: Favoriting System - models associations

I have the following model associations setup were a consumer can favorite a product or a variant. I just wanted to ask if my approach is correct?
class Favorite < ApplicationRecord
belongs_to :consumer
belongs_to :favorited, polymorphic: true
belongs_to :product, optional: true
belongs_to :variant, optional: true
end
class Consumer < ApplicationRecord
has_many :favorites
has_many :favorite_products, through: :favorites, source: :favorited, source_type: 'Product'
has_many :favorite_variants, through: :favorites, source: :favorited, source_type: 'Variant'
end
class Product < ApplicationRecord
has_many :favorites, dependent: :destroy
end
class Variant < ApplicationRecord
has_many :favorites, dependent: :destroy
end
class CreateFavorites < ActiveRecord::Migration[6.0]
def change
create_table :favorites do |t|
t.references :consumer, index: true
t.references :favorited, polymorphic: true, index: true
t.integer :product_id
t.integer :variant_id
t.timestamps
end
end
end
It is not clear why you have both polymorphic favorited and separate relation on product_id/variant_id. Usually one would go with one of these approaches.
Polymorphic associations can be unidirectional too - has_many :favorites, as: :favorited, dependent: :destroy
If you go with separate columns for each relation - indexes on product_id and variant_id may also be useful to prevent full table scan on product/variant deletion (on dependent: :destroy, also if you do not expect callbacks/nested relations there - delete_all is faster).

Implement a "Likes system" in rails

I'm trying to figure out how to setup the following. A user can create a review and then like his review or like other reviews if he wants to. I came up with the following setup:
class Like < ApplicationRecord
belongs_to :user
belongs_to :review
end
class User < ApplicationRecord
has_many :reviews
has_many :likes
has_many :liked_reviews, through: :likes, source: :review
end
class Review < ApplicationRecord
belongs_to :user
has_many :likes
has_many :liking_users, :through => :likes, :source => :user
end
class CreateLikes < ActiveRecord::Migration[6.0]
def change
create_table :likes do |t|
t.references :user, index: true
t.references :likes, index: true
t.integer :review_id
t.timestamps
end
end
end
I'm pretty sure that the model associations I came up with are correct, but I'm not so sure about the like table. Can someone please review the above and tell me if the model associations and like table are correct? Thanks in advance!

How do i associate a model_id to a nested model of third level?

my model structure looks like this
resources :genres do
resources :stories do
resources :episodes do
resources :comments
end
end
end
I have already added an episode_id to the comments table. However when i added genre_id and story_id to comments table and check for it in the console, genre_id and story_id was given Nil.
`
Comment.rb
class Comment < ApplicationRecord
belongs_to :episode
belongs_to :story
belongs_to :user
end
Genre.rb
class Genre < ApplicationRecord
belongs_to :user
has_many :stories, dependent: :destroy
end
Story.rb
class Story < ApplicationRecord
belongs_to :genre
belongs_to :user
has_many :comments
has_many :episodes, dependent: :destroy
has_attached_file :image, size: { less_than: 1.megabyte }, styles:{ medium: "300x300#", wide: "200x400#" }
validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/
scope :of_followed_users, -> (following_users) { where user_id: following_users }
end
Firstly, you can't associate comment belongs to more models without set otional: true, because your comment will require ids for all associated models.
class Comment < ApplicationRecord
belongs_to :episode, optional: true
belongs_to :story, optional: true
belongs_to :user
end
I sugest you to use this example.
change comment table with this migration
def change
add_column :comments, :commentable_type, :string
add_column :comments, :commentable_id, :integer
add_column :comments, :user_id, :integer
end
class Comment < ApplicationRecord
belongs_to :commentable, polymorphic: true
end
class User < ApplicationRecord
has_many :comments
end
class Genre < ApplicationRecord
...
has_many :comments, as: :commentable, depented: :destroy
end
class Story < ApplicationRecord
...
has_many :comments, as: :commentable, depented: :destroy
end
now you can Story.last.comments.new => .., commentable_id: story_last_id, commentable_type: 'Story'
more about polymorphic associations

Rails 4: can a child model belong_to two different parent models

In my initial Rails 4 app, I had the following models:
User
has_many :administrations
has_many :calendars, through: :administrations
has_many :comments
Calendar
has_many :administrations
has_many :users, through: :administrations
has_many :posts
has_many :comments, through: :posts
Administration
belongs_to :user
belongs_to :calendar
Post
belongs_to :calendar
has_many :comments
Comment
belongs_to :post
belongs_to :user
I just added a new Ad model to the app:
Ad
belongs_to :calendar
And now I would like to allow users to write comments about the ad records.
Can I use my existing Comment model and do something like:
Ad
belongs_to :calendar
has_many :comments
Comment
belongs_to :post
belongs_to :user
Or do I need to create a distinct "Comment" model, that I would call for instance AdComments or Feedback?
You need to use polymorphic associations. Something on the lines of this:
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
end
class Ad < ActiveRecord::Base
has_many :comments, as: :commentable
end
class Product < ActiveRecord::Base
has_many :comments, as: :commentable
end
And the migration would look like:
class CreateComments < ActiveRecord::Migration
def change
create_table :comments do |t|
t.references :commentable, polymorphic: true, index: true
t.timestamps null: false
end
end
end
I guess you already have the comments table, so you should rather change the table with
class ChangeComments < ActiveRecord::Migration
def change
change_table :comments do |t|
t.rename :post_id, :commentable_id
t.string :commentable_type, null: false
end
end
end
Also beware, that if you have live data you should update the commentable_type field of all already existing comments to Post. You can either do it in a migration or from the console.
Comment.update_all commentable_type: 'Post'
We don't need to use any new model, you can just refactor the current Comment model with polymorphic
So, a comment always belongs to a user, and belongs to a post or ad

Resources