winston
winston

Reputation: 3100

ActiveRecord::RecordNotFound - Couldn't find without an ID

I'm working on an app that allows users to comment on a single "work" (think blog post). The associations in the models are as follows:

class User < ActiveRecord::Base
  has_many :works  
  has_many :comments


class Work < ActiveRecord::Base
  belongs_to :user
  has_many :comments

class Comment < ActiveRecord::Base
  belongs_to :user
  belongs_to :post
  belongs_to :work

There's a form on the Works show page that allows users to post a comment:

<%= form_for(@comment) do |f| %>
  <%= render 'shared/error_messages', object: f.object %>
  <div class="field">
    <%= f.text_area :content, placeholder: "Post a comment!" %>
  </div>
  <%= f.submit "Post", class: "btn btn-small btn-primary" %>
<% end %>

The Works controller is as follows. Note that I'm adding the build comment functionality here so that the form on the Works page functions:

class WorksController < ApplicationController
   #before_filter :current_user,   only: [:edit, :update]

  def index
    @works = Work.all
    @comment = @work.comments.build(params[:comment])
    @comment.user = current_user

respond_to do |format|
  format.html # index.html.erb
  format.xml  { render :xml => @works }
end
end
def create
    @work = current_user.works.create(params[:work])
    redirect_to current_user
  end

def edit
    @work = current_user.works.find(params[:id])
end

def new
  @work = current_user.works.new
end

def destroy
  @work = current_user.works.find(params[:id]).destroy
  flash[:success] = "Work deleted"
  redirect_to current_user
end

 def update
    @work = current_user.works.find(params[:id])
    if @work.update_attributes(params[:work])
      flash[:success] = "Profile updated"
      redirect_to @work
    else
      render 'edit'
    end
  end


  def show 
  @work = Work.find(params[:id])
  @comment = @work.comments.build
  @comment.user = current_user
  @activities = PublicActivity::Activity.order("created_at DESC").where(trackable_type: "Work", trackable_id: @work).all
  @comments = @work.comments.order("created_at DESC").where(work_id: @work ).all 
    respond_to do |format|
      format.html # show.html.erb
      format.xml  { render :xml => @work }
    end
  end
end

And lastly, here is the Comments controller:

class CommentsController < ApplicationController

  before_filter :authenticate_user!

  def index
    @comments = Comment.all
  end

  def show
    @comment = Comment.find(params[:id])
    @activities = PublicActivity::Activity.order("created_at DESC").where(trackable_type: "Comment", trackable_id: @comment).all
   respond_to do |format|
      format.html # show.html.erb
      format.xml  { render :xml => @comment }
  end

  def update
     @comment = current_user.comments.find(params[:id])
    if @comment.update_attributes(params[:comment])
      flash[:success] = "Comment updated"
      redirect_to @comment
    end
  end

  def create
    @work = Work.find(params[:id])
    @comment = @work.comments.build(params[:comment])
    @comment.user = current_user
    if @comment.save
      #flash[:success] = "Post created!"
      redirect_to @work
    else
      render 'home#index'
    end
  end
  end
end

When I attempt to submit a comment using the comment form on the works show view page, I get the following error:

Activerecord::RecordNotFound in CommentsController#create

Couldn't find Work without an ID

Why can't the application find the Work so that it can associate the comment to it?

EDIT 1: Thanks to the answers below I edited the comment form:

<%= form_for(@work, @comment) do |f| %>
  <%= render 'shared/error_messages', object: f.object %>
  <div class="field">
    <%= f.text_area :content, placeholder: "Post feedback or contribute content
    to this work!" %>
  </div>
  <%= f.submit "Post", class: "btn btn-small btn-primary" %>
<% end %>

I'm still getting the same error after making the change to the form and adding the nested route.

I edited the routes file to include a nest for work comments:

    authenticated :user do
    root :to => 'activities#index'
  end
  root :to => "home#index"
  devise_for :users
  resources :users do
    member do
      get :following, :followers, :posts, :comments
    end
  end
  resources :works do
    resources :comments
  end
  resources :relationships, only: [:create, :destroy]
  resources :posts
  resources :activities
  resources :comments

Rake routes shows the following for Comments#create: POST /comments(.:format)

The POST URL (where the error shows up) is appURL/works/1/comments

Doesn't seem right. What do I need to change? Thank you so much for the help so far!!

Upvotes: 1

Views: 10071

Answers (2)

sevenseacat
sevenseacat

Reputation: 25049

Your form needs to be form_for([@work, @comment]) so that Rails knows to build a URL like /works/123/comments. Right now it would just be posting to /comments.

Check your rake routes to see the route for your CommentsController#create action. You might also need to tweak the controller to read params[:work_id] instead of params[:id].

Upvotes: 3

rossta
rossta

Reputation: 11504

The view helper form_for(@comment) will post to '/comments' by default. You can specify a url (see the guides) that includes the :id of the work record. The typical approach is to use form_for([@work, @comment]) and Rails will do this for you so long as you've set up your routes with comments as a nested resource of work.

Upvotes: 1

Related Questions