Reputation: 7121
I have two controllers: tasks
and workers
.
I visited localhost:3000/workers
. When I pressed "Add a New Task" (this is the link I put: <%= link_to 'Add a New Task', new_worker_path %>
), I got errors:
NoMethodError in Workers#new
Showing /home/alon/projects/todo/app/views/workers/new.html.erb where line #3 raised:
undefined method `tasks_path' for #<#<Class:0xb663ccf0>:0xb663b3c8>
Extracted source (around line #3):
1: <h1>New task</h1>
2:
3: <%= form_for @workers do |f| %>
4: <p>
5: <%= f.label :name %><br />
6: <%= f.text_field :name %>
Rails.root: /home/alon/projects/todo
Application Trace | Framework Trace | Full Trace
app/views/workers/new.html.erb:3:in `_app_views_workers_new_html_erb___132490529__619346358'
app/controllers/workers_controller.rb:28:in `new'
Request
Parameters:
None
Show session dump
Show env dump
Response
Headers:
None
Why did I get these errors?
I created the files _form.html.erb
, index.html.erb
, new.html.erb
, show.html.erb
, and edit.html.erb
in views/workers
.
I defined in routes.rb
:
resources :workers do
resources :tasks
end
This is my workers_controller
:
class WorkersController < ApplicationController
def index
@workers = Task.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: @workers }
end
end
# GET /workers/1
# GET /workers/1.json
def show
#.find(params[:id])
@workers = Task.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: @workers }
end
end
# GET /workers/new
# GET /workers/new.json
def new
@workers = Task.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: @workers }
end
end
# GET /workers/1/edit
def edit
@worker = Task.find(params[:id])
end
# POST /workers
# POST /workers.json
def create
@worker = Task.new(params[:task])
respond_to do |format|
if @worker.save
format.html { redirect_to @worker, notice: 'Your task was created.' }
format.json { render json: @worker, status: :created, location: @worker }
else
render "new"
end
end
end
# PUT /workers/1
# PUT /workers/1.json
def update
@worker = Task.find(params[:id])
respond_to do |format|
if @worker.update_attributes(params[:task])
format.html { redirect_to @worker, notice: 'Task was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: @worker.errors, status: :unprocessable_entity }
end
end
end
# DELETE /workers/1
# DELETE /workers/1.json
def destroy
@worker = Task.find(params[:id])
@worker.destroy
respond_to do |format|
format.html { redirect_to tasks_url }
format.json { head :no_content }
end
end
end
In addition, I wrote the next code in models/tasks.rb
:
class Task < ActiveRecord::Base
belongs_to :Worker
attr_accessible :done, :name, :task
end
This is my workers/new.html.erb
file:
<h1>New task</h1>
<%= form_for @workers do |f| %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<p>
<%= f.label :task %><br />
<%= f.text_area :task %>
</p>
<p>
<%= f.label :done %><br />
<%= f.check_box :done %>
</p>
<p>
<%= f.submit "add a new task" %>
</p>
<% end %>
and this is workers/_form.html.erb
:
<%= form_for(@task) do |f| %>
<% if @task.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@task.errors.count, "error") %> prohibited this task from being saved:</h2>
<ul>
<% @task.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :task %><br />
<%= f.text_area :task %>
</div>
<div class="field">
<%= f.label :done %><br />
<%= f.check_box :done %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Upvotes: 0
Views: 498
Reputation: 96484
If you type rake routes you will see:
$ rake routes
worker_tasks GET /workers/:worker_id/tasks(.:format) tasks#index
POST /workers/:worker_id/tasks(.:format) tasks#create
new_worker_task GET /workers/:worker_id/tasks/new(.:format) tasks#new
...
So new_worker_task
will give you a new task for the worker in question when you pass the worker in.
<%= link_to 'Add a New Task', new_worker_task_path(worker) %> # (below)
I recreated your app locally and got it to work with:
<table>
<tr>
<th></th>
<th></th>
<th></th>
</tr>
<% @workers.each do |worker| %>
<tr>
<td><%= link_to 'Show', worker %></td>
<td><%= link_to worker.name, worker %></td>
<td><%= link_to 'Edit', edit_worker_path(worker) %></td>
<td><%= link_to 'New Task', new_worker_task_path(worker) %>
<td><%= link_to 'Destroy', worker, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</table>
Note that I added a 'name' attribute for worker to make them easier to show (added it to the form and the index pages and of course a db migration to add it to the db).
As pjammer points out you can also do this through nested_attributes in forms, e.g. form_for([@worker, @task])
Upvotes: 2
Reputation: 9577
you seem to be using nested routes but are passing in Task.new
instead of something like Worker.new
and if you want to add tasks to the worker, use accepts_nested_attributes_for
or create a Form Object to handle the creation of tasks.
Upvotes: 1