我有一个名为Tasklist的对象,它有很多任务。很简单。但Tasklist属于User。我试图从任务列表显示页面创建一个新任务,并且我在如何做到这一点上遇到了很多麻烦。我会发布代码并进一步解释我的问题。任何帮助都会很棒!谢谢。
def show
@tasklist = current_user.tasklists.find(params[:id])
@task = @tasklist.tasks.new
end
<h1>page<%= @tasklist.name %></h1>
<%= form_for @task do |form| %>
<%= form.label :description %>
<%= form.text_field :description %>
<%= form.submit %>
<% end %>
def create
current_user.tasklists.tasks.create(task_params)
end
private
def task_params
params.require(:task).permit(:description)
end
尝试从显示页面创建对象后出现错误。
## ERROR
NoMethodError in TasksController#create
undefined method `tasks' for #<Tasklist::ActiveRecord_Associations_CollectionProxy:0x007faa4263b520>
def create
current_user.tasklists.tasks.create(task_params)
end
答案 0 :(得分:4)
用户tasklists
返回一组记录,您尝试在其上调用实例方法#tasks
。
想一想 - ActiveRecord应该如何知道您尝试添加任务的集合中的哪个task_list?
首先,你需要解开你的联想:
class User < ActiveRecord::Base
has_many :task_lists
has_many :tasks, through: :task_lists
end
class TaskList < ActiveRecord::Base
belongs_to :user
has_many :tasks
end
class Task < ActiveRecord::Base
belongs_to :task_list
# dont use belongs_to as Rails will not keep the relation up
# to date!
has_one :user, through: :task_list
end
基本上我们在User
和Task
之间建立间接关系,并确保不重复实际的外键列。
您想要的是nested resource:
resources :task_lists, shallow: true do
resources :tasks
end
这将为您提供这些路线(运行rake routes
以查看全部)
Prefix Verb URI Pattern Controller#Action
task_list_tasks GET /task_lists/:task_list_id/tasks(.:format) tasks#index
POST /task_lists/:task_list_id/tasks(.:format) tasks#create
new_task_list_task GET /task_lists/:task_list_id/tasks/new(.:format) tasks#new
这意味着我们可以从params[:task_list_id]
获取任务列表。
class TasksController < ApplicationController
before_action :set_task_list, only: [:new, :create, :index]
# POST /task_lists/:task_list_id/tasks
def create
@task = @task_list.tasks.new(task_list_params)
if @task.save
redirect_to @task_list, success: 'Task created.'
else
render 'tasks/show'
end
end
private
def set_task_list
@task_list = TaskList.includes(:tasks)
.where(user: current_user)
.find(params[:task_list_id])
end
def task_list_params
params.require(:task).permit(:description)
end
end
由于我们有has_one :user, through: :task_list
,因此在创建任务时我们不必担心current_user。我们只需在task_list中添加一个。
现在让我们更新表单,使其指向正确的资源:
<h1>page<%= @tasklist.name %></h1>
<%= form_for[@tasklist, @task] do |form| %>
<%= form.label :description %>
<%= form.text_field :description %>
<%= form.submit %>
<% end %>