Как я могу реализовать возможность добавления новой задачи в существующий список (проект) или в новый

#ruby-on-rails

#ruby-on-rails

Вопрос:

Мне нужна возможность добавления новой задачи в существующий список (проект) или в новый. У меня есть 2 модели: Project и Todo. Project has_many :todos, Todo belongs_to:project Я написал некоторый код, который дает мне возможность создавать задачи

 class Api::V1::TodosController < ApiController


 skip_before_action :verify_authenticity_token



  def create@todo = Todo.new(todo_params_on_create)



    if @todo.save

      render json: @todo, status: :createdelse

      render json: @todo.errors, status: :unprocessable_entityend


  end



  private

  def todo_params_on_create

    params.require(:todo).permit(:text, :checked, :project_id)

  end
end
 

Но я могу создать задачу только для существующего проекта из-за ассоциации, и мне нужно передать project_id в запросе todos
Не могли бы вы помочь, как я могу реализовать создание новой задачи с помощью нового проекта?

PS Я подумал, что мне нужно реализовать какой-то метод в модели проекта и вызвать его перед сохранением новой задачи. Может быть, что-то вроде этого (но передайте значение заголовка в запросе todos):

 class Project < ApplicationRecord

  has_many :todos
  before_save :new_project, unless: :self.nil?



  def new_projectself.update_columns(title: "NewProject")

  end



end
 

Но я думаю, что я ошибаюсь в своих мыслях.

Комментарии:

1. Использовать belongs_to :project, optional: true в модели задач.

2. @kishorecheruku спасибо за совет! Как я могу создать задачу в связи с новым проектом? Чтобы при создании новой задачи одновременно создавался новый проект с заполненным значением заголовка, а новая задача была связана с новым проектом.

3. Вы хотите иметь nested_attributes для модели проекта. Вот хороший пример с объяснением и примером.

Ответ №1:

Для создания элемента Todo без проекта используйте, как указано в комментарии belongs_to :project, optional: true

Для создания вашего элемента Todo вместе с новым проектом

Некоторые быстрые грязные способы заключаются в том, чтобы просто создать объект Project перед созданием объекта Todo в вашем контроллере Todo (если вы хотите, чтобы он был создан только с помощью этого контроллера)

 class Api::V1::TodosController < ApiController 
  def create
    todo = Todo.new(todo_params_on_create)
    if todo.project_id.nil?
      project = Project.create(title: "NewProject")
      todo.project_id = project.id
    end
    if todo.save    
      render json: todo, status: :create
    else
      render json: todo.errors, status: :unprocessable_entity
    end
  end
end
 

или в вашей модели Todo (если вы хотите использовать ее всякий раз, когда создается задача Todo)

 class Todo < ApplicationRecord

  before_create :create_project, unless: :project_id

  def create_project
    project = Project.create(title: "NewProject")
    self.project_id = project.id
  end
end
 

Проблема с этим подходом заключается в том, что в случае сбоя создания объекта Todo в вашей базе данных все равно будет создан объект Project. Решением этой проблемы было бы удаление объекта Project в случае сбоя, но это все равно может привести к ошибкам.

Более правильным решением является просто использовать транзакции и обработку ошибок для обработки создания / удаления объектов, но это также сопряжено с дополнительными накладными расходами:

 class Api::V1::TodosController < ApiController 
  def create
    begin
      ActiveRecord::Base.transaction do
        todo = Todo.new(todo_params_on_create)
        if todo.project_id.nil?
          project = Project.create!(title: "NewProject")
          todo.project_id = project.id
        end
        todo.save!
        render json: todo, status: :create
      end
    rescue StandardError => e
      //Handle error message
    end
  end
end
 

Комментарии:

1. Спасибо за совет! И как я могу вместо жестко заданного заголовка передать значение заголовка в запросе при создании задачи?

2. title: params[:title] если у вас есть заголовок, переданный в качестве параметра