Search code examples
ruby-on-railsfor-loopruby-on-rails-5nested-attributesaccepts-nested-attributes

param is missing or the value is empty: task. How can I make possible to add a "To Do" while also rendering the view to create a project?


I want that when the user creates a project s/he could also add new tasks into it. I have figured out this "solution" and I have encountred this error that I can't solve.

I dont even know of it is "ruby correct" that I mix tasks actions with the projects controller. The reason I took this approach is that I couldn't figure out for a solution for doing so in the views and make the project be saved..

This is my projects_controler.rb

  class ProjectsController < ApplicationController
  before_action :set_project, only: [:show, :edit, :update, :destroy]
  before_action :authenticate_user!

  def create
    @project = Project.new(project_params)
    @task = Task.new(task_params)

    respond_to do |format|
      if @project.save and @task.save
        format.html { redirect_to @project, notice: 'Project was successfully created.' }
        format.json { render :show, status: :created, location: @project }
      else
        format.html { render :new }
        format.json { render json: @project.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /projects/1
  # PATCH/PUT /projects/1.json
  def update
     respond_to do |format|
     if @project.update(project_params)
        format.html { redirect_to @project, notice: 'Project was successfully updated.' }
        format.json { render :show, status: :ok, location: @project }
      else
        format.html { render :edit }
        format.json { render json: @project.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /projects/1
  # DELETE /projects/1.json
  def destroy
    # @list = List.find(params[:id])
    @project.destroy
    respond_to do |format|
      format.html { redirect_to projects_url, notice: 'Project was successfully destroyed.' }
  format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_project
      @project = Project.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def project_params
      params.require(:project).permit(:title, :description, :done, :user_id)
    end



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

    def task_params
      params.require(:task).permit(:title, :done, :project_id)
    end
end

project.rb

class Project < ApplicationRecord
  belongs_to :user, foreign_key: "user_id"
  has_many :tasks , dependent: :destroy
  validates_presence_of :user
  validates_uniqueness_of :title, on: :create, message: "must be unique"
  validates :title, presence: true, length: { minimum: 2 }

    def done_tasks
     tasks.where(done: true).order("updated_at DESC")
  end
end

task.rb

class Task < ApplicationRecord
  belongs_to :project, foreign_key: "project_id"#, class_name: "List"
  validates_presence_of :title

  def completed?
    !completed_at.blank?
  end 
end

routes.rb

Rails.application.routes.draw do

  devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }

    resources :projects do
        resources :tasks
    end


  authenticated :user do
    root to: 'projects#index'
  end
  unauthenticated :user do
    root 'welcome#home'
  end
end

new.html.erb

<h1>New Project</h1>

<%= render 'form', project: @project, task: @task %>
<%# render 'form', project: @project, task: @task %>

  <!-- custom -->
  <!-- shall I ADD ID TO THE projrct t be trackable by the task????? and describe that in task.rb -->
  <!-- <h1>Tasks</h1> -->
  <%# f.button %>
<!-- button to add a new task -->
<%# f.button "add a new task to the current project" %>

<!-- if else mechanism for adding a new task via a button  -->
<!-- when button pressed, tasks/_form will appear down here -->
<!-- button to save the task while at the same moment  .....  override "create task" and "create project" to save "save project to task" -->

<%# render '../tasks/_form' %>

<%= link_to 'Back', projects_path %>

_form.html.erb

<%= simple_form_for(@project, @task) do |f| %>
<%# form_for([@post, @comment]) do |f| %>

  <% f.error_notification %>

  <div class="form-inputs">
    <%= f.input :title %>
    <%= f.input :description %>
    <%= f.input :done %>
    <%= f.association :user %>
  </div>



  <div class="form-actions">
    <%= f.button :submit %>
  </div>
<% end %>

Solution

  • In task_params

    params.require(:task).permit(:title, :done)
    

    and create method should be like

    def create
      @project = Project.new(project_params)
      @project.tasks.build(task_params)
    
      respond_to do |format|
        if @project.save and @task.save
          format.html { redirect_to @project, notice: 'Project was successfully created.' }
          format.json { render :show, status: :created, location: @project }
        else
          format.html { render :new }
          format.json { render json: @project.errors, status: :unprocessable_entity }
        end
      end
    end