创建属于另一个的对象 - 了解 Rails 关联
Creating an object that belong to another - Understand Rails Associations
我有一个名为 Tasklist 的对象,其中包含许多任务。很简单。但是任务列表属于用户。我正在尝试从任务列表显示页面创建一个新任务,但我在弄清楚如何做到这一点时遇到了很多麻烦。我将 post 编写代码并进一步解释我的问题。任何帮助都会很棒!谢谢。
任务列表控制器
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
用户 tasklists
returns 记录集合,您正试图对其调用实例方法 #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 %>
我有一个名为 Tasklist 的对象,其中包含许多任务。很简单。但是任务列表属于用户。我正在尝试从任务列表显示页面创建一个新任务,但我在弄清楚如何做到这一点时遇到了很多麻烦。我将 post 编写代码并进一步解释我的问题。任何帮助都会很棒!谢谢。
任务列表控制器
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
用户 tasklists
returns 记录集合,您正试图对其调用实例方法 #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 %>