关于ruby:缺少所需的键轨

Missing required keys rails

我正在尝试在app中创建任务表单.App有两个实体:

  • 项目belongs_to用户
  • 任务belongs_to项目

但是当我试图创建这个(非常基本的)表单时,我在我的视图中得到了这个错误

1
No route matches {:action=>"index", :controller=>"tasks"} missing required keys: [:project_id]

以下是我对此表单的看法的一部分

1
2
3
4
        <%= form_for [@project, @task],url: project_tasks_path do |f| %>
          <%= f.input :body,class: 'form-control' %>
          <%= f.submit 'Add task', class: 'btn' %>
        <% end %>

这是项目控制器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
class ProjectsController < ApplicationController
  before_action :load_project, only: [:show, :edit, :update, :destroy]
  before_action :authenticate_user!


  def index
    @projects = current_user.projects unless current_user.nil?
    @task = Task.find_by(params[:project_id])
  end

  def show
    @task = @project.tasks.build
  end

  def new
    @project = current_user.projects.new
  end

  def edit
  end

  def create
    @project = current_user.projects.create(project_params)

    if @project.save
      redirect_to root_path
    else
      render :new
    end
  end

  def update
    if @project.update(project_params)
      redirect_to @project
    else
      render :edit
    end
  end

  def destroy
    @project.destroy
    redirect_to projects_path
  end

  private

  def load_project
    @project = Project.find(params[:id])
  end

  def project_params
    params.require(:project).permit(:name, :user_id)
  end

end

和任务控制器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
class TasksController < ApplicationController
  before_action :set_task, only: [:show, :edit, :update, :destroy]
  before_action :authenticate_user!

  def index
    @tasks = Task.where(project_id: project_id)
  end

  def show
    project = Project.find_by(id: params[:project_id])
    @task = Task.new(project: project)
  end

  def new
    project = Project.find_by(id: params[:project_id])
    @task = Task.new(project: project)
  end


  def edit
    project = Project.find_by(id: params[:project_id])
    @task = Task.new(project: project)
  end

  def references
    respond_to do |format|
      if @task.valid?
        format.html { redirect_to root_url }
        format.json { render :show, status: :created, location: @task }
      else
        format.html { render :home_url }
        format.json { render json: @task.errors, status: :unprocessable_entity }
      end
    end
  end

  def create
    @project = Project.find_by(id: params[:project_id])
    @task = @project.tasks.create(task_params)

    respond_to do |format|
      if @task.valid?
        format.html { redirect_to root_url }
        format.json { render :show, status: :created, location: @task }
      else
        format.html { render :home_url }
        format.json { render json: @task.errors, status: :unprocessable_entity }
      end
    end
  end


  def update
    respond_to do |format|
      if @task.update(task_params)
        format.html { redirect_to root_url }
        format.json { render :home_url, status: :ok, location: @task }
      else
        format.html { render :root_url }
        format.json { render json: @task.errors, status: :unprocessable_entity }
      end
    end
  end

  def edit
  end

  def destroy
    @task.destroy
    respond_to do |format|
      format.html { redirect_to root_url }
      format.json { head :no_content }
    end
  end

  private
    def set_task
      @task = Task.find(params[:id])
    end

    def task_params
      params.require(:task).permit(:deadline, :body, :project_id)
    end
end

路线档案:

1
2
3
4
5
6
7
devise_for :users, :controllers => { :omniauth_callbacks =>"callbacks" }
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
  root 'projects#index'

  resources :projects do
    resources :tasks
  end

我的路线:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
projects#index
                   project_tasks GET      /projects/:project_id/tasks(.:format)          tasks#index
                                 POST     /projects/:project_id/tasks(.:format)          tasks#create
                new_project_task GET      /projects/:project_id/tasks/new(.:format)      tasks#new
               edit_project_task GET      /projects/:project_id/tasks/:id/edit(.:format) tasks#edit
                    project_task GET      /projects/:project_id/tasks/:id(.:format)      tasks#show
                                 PATCH    /projects/:project_id/tasks/:id(.:format)      tasks#update
                                 PUT      /projects/:project_id/tasks/:id(.:format)      tasks#update
                                 DELETE   /projects/:project_id/tasks/:id(.:format)      tasks#destroy
                        projects GET      /projects(.:format)                            projects#index
                                 POST     /projects(.:format)                            projects#create
                     new_project GET      /projects/new(.:format)                        projects#new
                    edit_project GET      /projects/:id/edit(.:format)                   projects#edit
                         project GET      /projects/:id(.:format)                        projects#show
                                 PATCH    /projects/:id(.:format)                        projects#update
                                 PUT      /projects/:id(.:format)                        projects#update
                                 DELETE   /projects/:id(.:format)                        projects#destroy

有人可以帮我澄清问题出在哪里,问题是什么?


问题出在您的TasksController#index操作上。什么是project_id?为了访问项目的任务,项目首先需要存在。而不只是那个。要访问任务的任何CRUD操作,必须首先存在项目。

将TasksController修改为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
class TasksController < ApplicationController
  before_action :set_project
  before_action :set_task, only: [:show, :edit, :update, :destroy]
  before_action :authenticate_user!

  def index
    @tasks = @project.tasks
  end

  def show
    #makes use of set_task
  end

  def new
    @task = @project.tasks.new
  end


  def edit
  end

  def references
    respond_to do |format|
      if @task.valid?
        format.html { redirect_to root_url }
        format.json { render :show, status: :created, location: @task }
      else
        format.html { render :home_url }
        format.json { render json: @task.errors, status: :unprocessable_entity }
      end
    end
  end

  def create
    @task = @project.tasks.create(task_params)
    respond_to do |format|
      if @task.valid?
        format.html { redirect_to root_url }
        format.json { render :show, status: :created, location: @task }
      else
        format.html { render :home_url }
        format.json { render json: @task.errors, status: :unprocessable_entity }
      end
    end
  end


  def update
    respond_to do |format|
      if @task.update(task_params)
        format.html { redirect_to root_url }
        format.json { render :home_url, status: :ok, location: @task }
      else
        format.html { render :root_url }
        format.json { render json: @task.errors, status: :unprocessable_entity }
      end
    end
  end


  def destroy
    @task.destroy
    respond_to do |format|
      format.html { redirect_to root_url }
      format.json { head :no_content }
    end
  end

  private

  def set_project
    @project = current_user.projects.find(params[:project_id]
  end

  def set_task
    @task = @project.tasks.find(params[:id])
  end

  def task_params
    params.require(:task).permit(:deadline, :body, :project_id)
  end
end

由于我们已经定义了before_action set_project,因此@project将可用于所有方法。请注意,set_project从当前用户创建的项目中查找项目。

在ProjectsController #index中,您实际上不会获得params[:project_id]的值。将索引操作修改为

1
2
3
def index
@projects = current_user.projects unless current_user.nil?
end

我不明白你的show方法。 build方法实际上用于创建对象的内存中表示。 projects_controller的show方法可用于显示项目及其任务。如果这是您所需要的,请将ProjectsController中的show操作更改为

1
2
3
4
def show
  #@project is available from load_project
  @tasks = @project.tasks
end

您也可以将load_project项目修改为

1
2
3
4
5
6
7
def load_project
  begin
    @project = Project.find(params[:id]) #raises an exception if project not found        
  rescue ActiveRecord::RecordNotFound
    redirect_to projects_path
  end
end

要了解有关拯救异常的更多信息,请参阅Ruby中的Begin,Rescue和Ensure?

有关详细信息,请参阅http://blog.8thcolor.com/en/2011/08/nested-resources-with-independent-views-in-ruby-on-rails/


如果要在projects / index.html.erb中创建新任务的表单,则应该为视图提供@task变量;尝试更改索引操作如下:

1
2
3
4
def index
  @projects = current_user.projects unless current_user.nil?
  @task = Task.new
end


问题在于提交表单的网址。如果检查rake routes,您会看到所有任务路径都嵌套在项目中,因此在传递url选项时,您应该具有以下内容:

1
2
3
4
    <%= form_for [@project, @task],url: project_tasks_path(@project) do |f| %>
      <%= f.input :body,class: 'form-control' %>
      <%= f.submit 'Add task', class: 'btn' %>
    <% end %>

甚至更好,我认为你应该能够在不传递url选项的情况下做到这一点:

1
2
3
4
     <%= form_for [@project, @task] do |f| %>
      <%= f.input :body,class: 'form-control' %>
      <%= f.submit 'Add task', class: 'btn' %>
    <% end %>

UPDATE

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def index
  project = Project.find(params[:project_id])
  @projects = ProjectsViewPresenter.new(project)
end

# presenters/projects_view_presenter.rb
class ProjectsViewPresenter
  attr_reader :project
  def initialize(project)
    @project = project
  end

  def tasks
   @tasks ||= project.tasks
  end

  def task
   @task ||= tasks.new
  end
end

您的form_for现在将是这样的:

1
2
3
4
    <%= form_for [@project.project, @project.task] do |f| %>
      <%= f.input :body,class: 'form-control' %>
      <%= f.submit 'Add task', class: 'btn' %>
    <% end %>