Save 36% for Black Friday! Learn more

All threads / How do I nest two resources that are both polymorphic associations?
Ask A Question

Notifications

You’re not receiving notifications from this thread.

How do I nest two resources that are both polymorphic associations?

snake117 asked in Rails

In my app, I have several models for various product types, as each product has different attribute types and I wanted to avoid using STI. However, I am using the same Review and Comment system for each of the Product resources. So for example, a path would be accessories/1/reviews/1/ and the New Comment form (and all comments for that review) will display under the specific Review.

I am taking the same approach as used in the following video: https://gorails.com/episodes/comments-with-polymorphic-associations?autoplay=1.

Right now, the New Comment form displays properly below the show review page, but when I try to create a new comment I receive the following error:

NameError at /accessories/1/reviews/1/comments
uninitialized constant Accessories::Reviews
activesupport (6.0.2.1) lib/active_support/inflector/methods.rb
279 280 281 282 283 284 285 286 287 288 289
      names.inject(Object) do |constant, name|
        if constant == Object
          constant.const_get(name)
        else
          candidate = constant.const_get(name)
          next candidate if constant.const_defined?(name, false)
          next candidate unless Object.const_defined?(name)

Here is all the relevant code I have:

views/reviews/show.html.erb:

    ...
      <%= render partial: "comments/form", locals: { reviewable: @reviewable, commentable: @review } %>
      <%= render partial: "comments/comments", locals: { reviewable: @reviewable, commentable: @review } %>
    ...

views/comments/_form.html.erb :

<%= form_for([reviewable, commentable, Comment.new]) do |f| %>
          <%= f.form_group :body, class: 'row' do |f| %>
            <div class='col-12 col-md-12'>
              <%= f.text_area :body, { class: 'form-control', placeholder: "Add a comment..." } %>
              <%= f.error_messages %>
            </div>
          <% end %>
          <div class="d-flex">
        <div class="ml-auto">
                    <%= f.submit class: "btn btn-primary pull-right" %>
                </div>
            </div>
        <% end %>

controllers/accessories/reviews_controller.rb:

class Accessories::ReviewsController < ReviewsController
    before_action :set_reviewable
    before_action :show_reviewable

    # GET /reviews
  def index
    @reviews = Review.where(reviewable_type: "Accessory", reviewable_id: params[:accessory_id])
  end

    private

        def set_reviewable
            @reviewable = Accessory.find(params[:accessory_id])
        end

        def show_reviewable
            @show_reviewable = Review.find_by_reviewable_type_and_reviewable_id("Accessory", params[:accessory_id]) 
        end
end

/controllers/accessories/comments_controller.rb:

class Reviews::CommentsController < CommentsController
    before_action :set_commentable

    private

        def set_commentable
            @commentable = Review.find(params[:review_id])
        end
end

/controllers/comments_controller.rb:

class CommentsController < ApplicationController
    before_action :authenticate_user!
    def create
        @comment = @commentable.comments.new(comment_params)
        @comment.user = current_user
        @comment.save
        redirect_to @commentable, notice: "Your comment was successfully posted!"
    end

    private

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

routes.rb:

...
  resources :accessories do 
    resources :reviews, module: :accessories do
      resources :comments, module: :reviews
    end
  end
    ...

accessory.rb:

class Accessory < ApplicationRecord
  belongs_to :user
  #has_rich_text :body
  has_many :reviews, as: :reviewable, dependent: :destroy
  #has_many :comments, as: :commentable, through: :reviews

  accepts_nested_attributes_for :reviews
  #accepts_nested_attributes_for :comments
    end

review.rb:

class Review < ApplicationRecord
  belongs_to :user
  belongs_to :reviewable, polymorphic: true
  has_rich_text :body
  has_many :comments, as: :commentable
    ...
    end

comment.rb:

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

Appreciate any guidance. Also, if there is a more efficient way to do this please let me know. Thanks!

Join the discussion

Want to stay up-to-date with Ruby on Rails?

Join 67,819+ developers who get early access to new tutorials, screencasts, articles, and more.

    We care about the protection of your data. Read our Privacy Policy.

    logo Created with Sketch.

    Screencast tutorials to help you learn Ruby on Rails, Javascript, Hotwire, Turbo, Stimulus.js, PostgreSQL, MySQL, Ubuntu, and more. Icons by Icons8

    © 2022 GoRails, LLC. All rights reserved.