Kamidesu
Kamidesu

Reputation: 111

undefined method `commentable' for #<ActiveRecord::Associations::CollectionProxy []> (accesing commentable id and type via polymorphic association)

I tried to fix this issue for a day but cannot find solution.

What I am doing now is to render the comment form

<%= form_for @comment, remote: true do |form|%>
  <%= form.hidden_field :question_id, value: @question.id%>
  <%= form.hidden_field :commentable_id, :value => @question.comments.commentable.id %>
  <%= form.hidden_field :commentable_type, :value => @question.comments.commentable.class.name %>
<% end %>

I just dont know how to access the commetable_id and type that was created with the comment controller to record the id of the comment and the type of the commenting model (e.g. client or lawyer)

  # GET /questions/1 or /questions/1.json
  def show
    set_question
    @comment = Comment.new
    @comments = Comment.all
  end
  # GET /questions/1 or /questions/1.json
  def show
    set_question
    @comment = Comment.new
    @comments = Comment.all
  end
  resources :questions do
    resources :comments do
    end
  end

Upvotes: 1

Views: 395

Answers (2)

Arun Kumar Mohan
Arun Kumar Mohan

Reputation: 11915

As the error message says, you can't call commentable on @question.comments - an association. Pass an array to the form_for method with the commentable (Question) object and the comment object. You don't need to set any hidden fields.

<%= form_for [@question, @comment] do |f| %>
  <div><%= f.label :content %></div>
  <div><%= f.text_area :content %></div>
  <div><%= f.submit 'Post' %></div>
<% end %>

Replace content with the field where you're storing the comment's content.

This should generate a form tag with an action attribute of /questions/1/comments which upon submission is processed by CommentsController#create.

class CommentsController < ApplicationController
  before_action :set_commentable

  def create
    @comment = @commentable.comments.new(comment_params)
    if @comment.save
      redirect_to @commentable, notice: 'Comment created'
    else
      render :new
    end
  end

  private

  def set_commentable
    # e.g. request.path => '/questions/1/comments'
    resource, id = request.path.split('/')[1, 2] # ['questions', '1']
    @commentable = resource.singularize.classify.constantize.find(id)
  end

  def comment_params
    params.require(:comment).permit(:content)
  end
end

In the set_commentable method, the commentable type and its id are detected from the request path. Since resource is 'questions', resource.singularize.classify.constantize returns the Question model. The commentable object is then found using the find method. The CommentsController#create method creates the comment and redirects to the commentable object which is the question show page (/questions/:id). If there's an error, it renders the new view (you have to create views/comments/new.html.erb to render the form with errors).

Upvotes: 1

honey
honey

Reputation: 1077

You are using question.comments which indicates has many relation, So it will return you an active record association array, So if you want to find the commentable id, you need to take single record from the array. For example if you want first comment commentable id, then use

   @question.comments.first.commentable.id

If each comment has different commentable id, you need to iterate through loop.

If you have some factor to apply condition, then apply the condition

   @question.comments.where('your condition').first.commentable.id

If you use above code, still you will get the array, so I have used .first. Use a uniq value in where condition, so you will have only single record with that value.

Upvotes: 1

Related Questions