How to associate a model with a model within a model?

76 Views Asked by At

When a user likes a comment create_notification is triggered in commet_like.rb:

class CommentLike < ActiveRecord::Base
  after_create :create_notification
  has_many :notifications
  belongs_to :user
  belongs_to :comment
  validates :user, uniqueness: { scope: :comment }
  belongs_to :liker, class_name: 'User', foreign_key: :user_id
  belongs_to :liked_comment, class_name: 'Comment', foreign_key: :comment_id

private

  def create_notification
    notifications.create(
      comment_like: self,
      comment:      comment,
      user:         comment.user,      
      read:         false
    )
  end
end

I'm trying to get something like this to work in the notifications index:

  <% if notification.comment_like_id %>
    <% if notification.goal_id %>
        liked <%= link_to "your comment", notification_goal_path(notification, notification.goal_id) %>
    <% elsif notification.habit_id %>
        liked <%= link_to "your comment", notification_habit_path(notification, notification.habit_id) %>
    <% elsif notification.quantified_id %>
        liked <%= link_to "your comment", notification_quantified_path(notification, notification.quantified_id) %>
    <% elsif notification.valuation_id %>
        liked <%= link_to "your comment", notification_valuation_path(notification, notification.valuation_id) %>
    <% end %>
  <% end %>

but the problem is that each of those conditionals are nil for comment_like therefore the notification is showing up blank.

As you can see here though CommentLike is associated with Comment, which in this example gives comment_id: 1 and comment_id: 1 has valuation_id: 1.

[1] CommentLike.find(1)
 id: 1,
 user_id: 1,
 comment_id: 1,
[2] Comment.find(1)
 id: 1,
 content: "test",
 goal_id: nil,
 habit_id: nil,
 valuation_id: 1,
 quantified_id: nil,
 commentable_id: nil,
 commentable_type: nil,
 user_id: 1,
 likes: 1>

How can we use this association to make the right conditional show up under comment_like_id according to comment's association with the 4 other models?

notifications_controller

  def index
    @notifications = current_user.notifications
    @notifications.each do |notification|
      notification.update_attribute(:read, true) 
    end
  end

comment.rb

class Comment < ActiveRecord::Base
  after_create :create_notification
  has_many :notifications
  has_many :comment_likes   
  has_many :likers, through: :comment_likes, class_name: 'User', source: :liker
  belongs_to :habit
  belongs_to :quantified
  belongs_to :valuation
  belongs_to :goal
  belongs_to :user

private

  def create_notification
    author = 
      if goal
        goal.user
      elsif habit
       habit.user
      elsif quantified
        quantified.user
      elsif valuation
        valuation.user
      end
    notifications.create(
      comment:      self,
      habit:        habit,
      quantified:   quantified,
      goal:         goal,
      valuation:    valuation,
      user:         author,      
      read:         false
    )
  end
end

Please let me know if you need further explanation or code :-]

2

There are 2 best solutions below

0
On BEST ANSWER

The key here was to use after_save :create_notification instead of after_create :create_notification and to also add the line likes: likes, to notifications.create(. After save works better because in the comment controller

I have this:

  def like
    @comment_like = current_user.comment_likes.build(comment: @comment)
    if @comment_like.save
      @comment.increment!(:likes)
      flash[:success] = 'Thanks for liking!'
    else
      flash[:error] = 'Too many likes'
    end  
    redirect_to(:back)
  end
3
On

Forgive me, since I don't really know what habit, quantified, etc are, but your code makes it look like they are things that could be commented on, therefore it seems like you should be using a polymorphic association.

class Comment < ActiveRecord::Base
  belongs_to :commentable, polymorphic: true
  has_many :notifications
  after_create :notify_user

  def notify_user
    self.notifications.create user: commentable.user
  end
end

class Habit < ActiveRecord::Base
  has_many :comments, as: :commentable
end

class Notification < ActiveRecord::Base
  belongs_to :comment
  belongs_to :user
  delegate :commentable, to: :comment
end

Here, by using the polymorphic relationship, we simplify everything quite a bit. Further, you can use the polymorphic route helper

<%= link_to "your comment", polymorphic_url(notification, commentable) %>

Hope this helps point you in the right direction