缺少所需的键轨

时间:2016-08-07 23:17:01

标签: ruby-on-rails ruby ruby-on-rails-4

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

  • 项目y[i] = x IndexError: list assignment index out of range 用户
  • 任务belongs_to项目

但是当我试图创建这个(非常基本的)表单时,我在我看来会出现这个错误

belongs_to

以下是我使用此表单的视图的一部分

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

这是项目控制器:

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

任务控制器:

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

路线档案:

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

我的路线:

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

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

3 个答案:

答案 0 :(得分:1)

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

将您的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

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

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

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

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

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

您还可以将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

要了解有关拯救例外的更多信息,请参阅Begin, Rescue and Ensure in Ruby?

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

答案 1 :(得分:0)

问题在于提交表单的网址。如果您检查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 %>

甚至更好,我认为你应该能够在不传递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 %>

<强>更新

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现在将是这样的:

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

答案 2 :(得分:0)

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

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