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!

Reply
Join the discussion
Create an account Log in

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

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

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