I'm sure I'm missing something simple, but not being aware of the right terminology in Rails, I can't find what I'm looking for....
A Project
model has_many Task
, and a Task
belongs_to a Project
.
My routes.rb
has
resources :projects
resources :tasks
I can create/edit/modify Projects
just fine, and I can also edit Tasks
... but I can't seem to work out how to create a new Task
, assigning the correct Project
when doing so.
My Project
page (eg. /projects/2) has an Add Task link which goes to /task/new, so I'm losing the connection. I don't want to make a nested resource, because Tasks
, once created, will be uniquely identifiable by their ID, and in future has_many other models as well.
Is there a quick fix here?
edit Well I've managed to solve this.... it's ugly and it's开发者_如何转开发 horrible and I'm not sure why it has to be that way, but it works.
My routes:
resources :projects do
resources :tasks, :only => [:new]
end
resources :tasks, :except => [:new]
My task controller:
def new
@project = Project.find(params[:project_id])
@task = @project.tasks.build
end
# Process the form for creating a new task.
def create
@project = Project.find(params[:task][:project_id])
@task = @project.tasks.build(params[:task])
if @task.save
flash[:success] = 'Task created.'
redirect_to project_path(@project)
else
render 'new'
end
end
And my Task form:
<%= semantic_form_for @task do |f| %>
<%= render 'shared/form_message', :object => f.object %>
<%= f.inputs do %>
<%= f.input :name %>
<%= f.input :project %>
<% end %>
<ul class="formActions">
<li class="list"><%= link_to 'Back to list', project_path(@task.project) %></li>
<li><%= f.submit "Save" %></li>
</ul>
<% end %>
I didn't want to have to put the project box on the form, and I'm still not sure why I have to, and also why I needed to take :create out of the nested routes. It also seems quite laborous, for such a common task, but it works, so.... I guess it's all good.
Make sure you build your new task through your project in your new task action so that it will come with the project ID already assigned. That should make your form generator behave nicely and do the right thing.
TasksController < AplicationController
before_filter :get_project
…
def new
@task = @project.tasks.build # don't use @task = Task.new here!
end
…
def get_project
@project = Project.find(params[:project_id])
end
end
of course it is highly recommended to use nested routes with this.
resources :projects do
resources :tasks
end
IT sounds like what you want is a nested route for creating tasks only.
resources :projects do
resources :tasks, :only=>[:new, :create]
end
resources :tasks, :except=>[:new, :create]
EDIT: Here's a revised version of your code that should be a bit cleaner. With a little borrowing from edgerunner.
Task controller:
before_filter :get_project
def new
@task = Task.new
end
# Process the form for creating a new task.
def create
@task = Task.new params[:task]
@task.project_id = params[:project_id]
if @task.save
flash[:success] = 'Task created.'
redirect_to project_path(@task.project_id)
else
render 'new'
end
end
private
def get_project
@project = Project.find(params[:project_id])
end
And the Task form:
<%= form_for [@project, @task] do |f| %>
<%= render 'shared/form_message', :object => f.object %>
<%= f.inputs do %>
<%= f.input :name %>
<% end %>
<ul class="formActions">
<li class="list"><%= link_to 'Back to list', project_path(@task.project) %></li>
<li><%= f.submit "Save" %></li>
</ul>
<% end %>
精彩评论