开发者

Create a child model in rails (belongs_to) and pre-setting the parent ID

开发者 https://www.devze.com 2023-02-05 09:15 出处:网络
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....

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 %>
0

精彩评论

暂无评论...
验证码 换一张
取 消