简体   繁体   English

缺少必需的按键导轨

[英]Missing required keys rails

I'm trying to create a form for task in my app.App has two entities: 我正在尝试为我的应用程序中的任务创建表单。应用程序有两个实体:

  • Project belongs_to User 项目belongs_to用户
  • Task belongs_to Project 任务belongs_to项目

But I get this error in my view when I'm trying to create this (pretty basic) form 但是,当我尝试创建此(相当基本的)表单时,出现了这个错误

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

Here is a part of my view with this form 这是我对此表格的看法的一部分

<div class="glyphicon glyphicon-plus col-xs-1 left_plus" ></div>
        <div class="col-xs-10" >
        <%= form_for [@project, @task],url: project_tasks_path do |f| %>
          <%= f.input :body,class: 'form-control' %>
          <%= f.submit 'Add task', class: 'btn' %>
        <% end %>

And here is the project controller: 这是项目负责人:

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

And the tasks controller: 和任务控制器:

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

The routes file: 路由文件:

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

And my routes: 而我的路线:

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

Can somebody please help me to clarify where is the problem and what is the problem? 有人可以帮我弄清楚问题出在哪里,问题出在哪里?

The problem is with your TasksController#index action. 问题出在您的TasksController#index操作上。 What is project_id there? 那里的project_id是什么? For accessing a project's tasks, the project needs to exist in the first place. 为了访问项目的任务,该项目首先需要存在。 And not just that. 不仅如此。 To access any CRUD action on tasks, a project has to exist first. 要访问对任务的任何CRUD操作,必须首先存在一个项目。

Modify your TasksController as 将您的TasksController修改为

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

Since we have defined a before_action set_project, @project will be available to all methods. 由于我们定义了before_action set_project,因此@project将对所有方法可用。 Note that set_project finds the project from the projects created by the current user. 请注意, set_project从当前用户创建的项目中查找项目。

In the ProjectsController#index, you won't actually get a value for params[:project_id] . 在ProjectsController#index中,实际上不会获得params[:project_id] Modify your index action to 修改索引操作为

def index
@projects = current_user.projects unless current_user.nil?
end

And I don't understand your show method. 而且我不了解您的show方法。 The build method is actually used to create a in-memory representation of an object. build方法实际上用于创建对象的内存表示。 The show method of projects_controller can be used to display the project along with its tasks. projects_controller的show方法可用于显示项目及其任务。 If this is what you need, change you show action in ProjectsController to 如果这是您需要的,请将您在ProjectsController中的show操作更改为

def show
  #@project is available from load_project
  @tasks = @project.tasks
end

You could also modify your load_project project as 您也可以将load_project项目修改为

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

To know more about rescuing exceptions, see Begin, Rescue and Ensure in Ruby? 要了解有关抢救异常的更多信息,请参见在Ruby中开始,抢救和确保?

For more, see http://blog.8thcolor.com/en/2011/08/nested-resources-with-independent-views-in-ruby-on-rails/ 有关更多信息,请参见http://blog.8thcolor.com/en/2011/08/nested-resources-with-independent-views-in-ruby-on-rails/

The problem is with the url for submitting the form. 问题在于提交表单的网址。 If you check your rake routes you'd see that all your task routes would be nested under projects, therefore in passing the url option, you should have something like: 如果检查rake routes您会看到所有任务路径都将嵌套在项目下,因此在传递url选项时,您应具有以下内容:

   <div class="glyphicon glyphicon-plus col-xs-1 left_plus" ></div>
    <div class="col-xs-10" >
    <%= form_for [@project, @task],url: project_tasks_path(@project) do |f| %>
      <%= f.input :body,class: 'form-control' %>
      <%= f.submit 'Add task', class: 'btn' %>
    <% end %>

or even better, I think you should be able to do that without passing the url option: 甚至更好,我认为您应该能够做到这一点而无需通过url选项:

    <div class="glyphicon glyphicon-plus col-xs-1 left_plus" ></div>
     <div class="col-xs-10" >
     <%= form_for [@project, @task] do |f| %>
      <%= f.input :body,class: 'form-control' %>
      <%= f.submit 'Add task', class: 'btn' %>
    <% end %>

UPDATE 更新

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

Your form_for would now be like this: 您的form_for现在将如下所示:

   <div class="glyphicon glyphicon-plus col-xs-1 left_plus" ></div>
    <div class="col-xs-10" >
    <%= form_for [@project.project, @project.task] do |f| %>
      <%= f.input :body,class: 'form-control' %>
      <%= f.submit 'Add task', class: 'btn' %>
    <% end %>

If the form to create a new task is in projects/index.html.erb you should make a @task variable available to the view; 如果用于创建新任务的表单位于projects / index.html.erb中,则应为视图提供@task变量; try to change the index action as follow: 尝试更改索引操作,如下所示:

def index
  @projects = current_user.projects unless current_user.nil?
  @task = Task.new
end

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM