Search code examples
ruby-on-railspolymorphic-associations

Retrieving data from polymorphic tables in rails


I have some polymorphic relationships set up and are working well for the primary purpose. That is for a User to be able to Comment on both Articles and Coffeeshops.

However I'm struggling with being able to display the users list of comments on their profile page. In the future I also want the user to be able to 'favourite' and 'want to go to' different coffeeshops which I would also want to show up on their profile page. I'm hoping once I get the logic for display current comments, the rest will be a breeze ;)

So what I have:

Models

class User < ApplicationRecord
  has_many :comments
end

class Comment < ApplicationRecord
  belongs_to :user
  belongs_to :commentable, polymorphic: true

end

class Coffeeshop < ApplicationRecord
  has_many :comments, as: :commentable
end

class Article < ApplicationRecord
  has_many :comments, as: :commentable

end

Comment Controller

class CommentsController < ApplicationController
  before_action :load_commentable
  before_action :authenticate_user!
  before_action :comment_auth, only:  [:edit, :update, :destroy]

  def index
    @comments = @commentable.comments
  end

  def new
    @comment = @commentable.comments.new
  end

  def create
    @comment = @commentable.comments.new(allowed_params)
    @comment.user_id=current_user.id if current_user
    if @comment.save
      redirect_to @commentable, notice: "Comment created."
    else
      render :new
    end

  end

  def update
    @comment = Comment.find(params[:id])
    if @comment.update(comment_params)
      redirect_to @commentable
    else
      render 'edit'
    end
  end

  def destroy
    @comment = Comment.find(params[:id])
    @commentable = @comment.commentable
    if @comment.destroy
      flash[:success] = "Comment Destroyed!"
      redirect_to :back
    end

    end

  private

  def allowed_params
  params.require(:comment).permit(:name, :body)
end

  def load_commentable
    resource, id = request.path.split('/')[1,2]
    @commentable = resource.singularize.classify.constantize.find(id)
  end


  def comment_params
     params.require(:comment).permit(:body).merge(user_id: current_user.id)
  end

Profile Controller

class ProfileController < ApplicationController
before_action :authenticate_user!

  def index

  end

  def show
    @user = User.find.current_user(params[:id])
    @comments = @commentable.comments

  end

In views/profile/show.html.erb. I was trying to do:

<h3>Your Latest Comment</h3>
<%=@comment.user.body%>

But this clearly isn't right as I get Couldn't find User without an ID. From ProfileController#show

update

If I change ProfileController to

before_action :authenticate_user!

  def index
    @user = User.find.current_user(params[:user_id])
  end

  def show
    @comments = @commentable.comments
  end

I get an error for undefined comments.


Solution

  • ok first return this to show moving it to index is not solving a problem the index is not called so write show like this.

    def show
     @user = current_user #you get instance of a user that is logged in
     @comments =  @user.comments
    end
    

    I do not know if you have user_id in your comment migration but if you do not have you must write

    class User < ApplicationRecord
      has_many :comments, as: :commentable
    end
    

    view

    <h3>Your Latest Comment</h3>
    <%=@comments.try(&:last).try(&:body)%>