Search code examples
ruby-on-railsruby-on-rails-5

undefined method `reviews' for #<User:0x00007fa70dc93f40>


I have 3 models in my app - User, Post & Review. A user has_many :posts, posts has_many :reviews.

To make a post or to drop a review the user should be logged in.

class ReviewsController < ApplicationController    
  def new
    @post = Post.find(params[:post_id])
    @review = Review.new
  end

  def create        
    @post = Post.find(params[:post_id])
    @review = @post.reviews
    @review = current_user.reviews.build(comment_params)
    if @review.save
      flash[:success] = "Hurray!!"
      redirect_to user_path(current_user)
    else
      flash.now[:danger] = "Hurray!!"
      render 'new'
    end

    # @review = current_user.review.post.new(comment_params)
    # @review.save
    # flash[:success] = "Comment Posted succesfully"
    # redirect_to user_path(current_user)

  end

  private

  def comment_params
  #  params.require(:review).permit(:comment)
  params.require(:reviews).permit(:comment)
  end    
end

View - Review#new

<div class="row">
  <div class="col-md-offset-3 col-md-8">
   <b> Add a review </b>
  </div>
</div>

<%= form_for [@post, @review] do |r| %>
  <div class="row">
   <div class="col-md-offset-3 col-md-7">
     <% render 'errors' %>
   </div>
  </div>
  <div class="row">
    <div class="col-md-offset-3 col-md-7">
      <div class="form-group">
        <%= r.label :comment %>
        <%= r.text_area :comment, class: "form-control" %>
      </div>
      <%= r.submit "Add", class: "btn btn-primary btn-block" %>
    </div>
  </div>
 <% end %>

Routes:

Rails.application.routes.draw do
  # root 'posts#index'
  root 'mains#home'
  resources :users 
  resources :posts do 
    resources :reviews
  end
  # resources :reviews
  resource :sessions, only: [:new, :create, :destroy]
  resources :passwords, only: [:new, :create, :edit, :update]    
end

Params from logs:

 {"authenticity_token"=>"XunDfWighjQFYPmGOuIBMXIaiKzNM1BEDiU5 
 OU2DxvZAvBCP+ERzYSEI/eA/FYIiEPKjo32BX6vqZDm2fQmHrQ==",
 "review"=> {"comment"=>"dsf"}, "commit"=>"Add", "post_id"=>"12"}

There is no user id anywhere. It is right to pass 'post_id' the way it is passing?

I hope I'm able able to explain the problem at least now.


Solution

  • You need to add user_id to Review model and associate them. User has_many :reviews and Review belongs_to :user. Add migration with

    def change
      add_reference :reviews, :user, foreign_key: true
    end
    

    And change the controller

    class ReviewsController < ApplicationController    
      def new
        @post = Post.find(params[:post_id])
        @review = @post.reviews.new
      end
    
      def create        
        @post = Post.find(params[:post_id])
        @review = @post.reviews.build(review_params)
        @review.user_id = current_user.id
        if @review.save
          flash[:success] = "Hurray!!"
          redirect_to user_path(current_user)
        else
          flash.now[:danger] = "Hurray!!"
          render 'new'
        end
      end
    
      private
    
      def review_params
        params.require(:review).permit(:comment)
      end    
    end
    

    And yes, it is correct to pass post_id to the controller