Rails - сохранение в таблице и обновление / создание в другой - PullRequest
1 голос
/ 15 октября 2019

Я создаю небольшое приложение для управления собственным онлайн-портфолио, но не могу решить проблему с update.

Основная таблица в моей базе данных - works, затем есть таблицы authors и clients, где я устанавливаю поля authorName и clientName как unique. Авторы и клиенты могут иметь несколько работ, но работа может иметь только одну из них.

В форме, где я создаю работы, у меня есть поле для authorName и еще одно для clientName: еслиавтора не существует в таблице авторов, он создается, в противном случае существующий связывается с работой. То же самое с клиентом. Для достижения этого я использую first_or_initialize, и он работает отлично. Проблемы начинаются, когда я пытаюсь использовать тот же метод внутри действия update. Это мои модели:

Рабочая модель

 class Work < ApplicationRecord

    has_one :description

    belongs_to :author
    belongs_to :client

    accepts_nested_attributes_for :client
    accepts_nested_attributes_for :author

    scope :active, lambda {where(:isActive => true)}
    scope :descOrder, lambda {order(:date => :desc)}
    scope :cover, lambda {where(:isCover => true)}

end 

Автор Модель

class Author < ApplicationRecord

    has_many :works

end

Модель клиента

class Client < ApplicationRecord

    has_many :works

end

Быстрое редактирование: модели в том виде, в каком вы их видите, точно такие же, как и в моем приложении. Код не был удален.

На мой взгляд, эта форма:

<%= form_for(@work, :url => { :controller => "projects", :action => "update"} ) do |f| %>
    <%= f.label("title") %>
    <%= f.text_field(:title) %>

    <%= f.fields_for(:author) do |author| %>
        <%= author.label("author") %>
        <%= author.text_field(:authorName) %>
    <% end %>

    <%= f.fields_for(:client) do |client| %>
        <%= client.label("client") %>
        <%= client.text_field(:clientName) %>
    <% end %>

    <%= f.label("date") %>
    <%= f.date_field(:date) %>


    <%= f.submit("update") %>
<% end %>

И вот как я обращаюсь с ней в контроллере:

def edit
  @work = Work.find(params[:id])

  if @work.client.nil?
    @work.build_client
  end

  if @work.author.nil?
    @work.build_author
  end
end

def update
  @work = Work.find(params[:id])

  @work.client = Client.where(clientName: work_params["client_attributes"]["clientName"]).first_or_initialize
  @work.author = Author.where(authorName: work_params["author_attributes"]["authorName"]).first_or_initialize

  if @work.update(work_params)
    flash[:notice] = "work: #{@work.title} updated successfully."
    redirect_to(project_path(@work))
  else
    redirect_to new_project_path
  end
end

private

def work_params
  params.require(:work).permit(:title, :date, client_attributes: [:id, :clientName], author_attributes: [:id, :authorName])
end

Это ошибка, которую я получаю:

Started PATCH "/projects/21" for ::1 at 2019-10-14 20:00:27 -0700
Processing by ProjectsController#update as HTML
  Parameters: {"authenticity_token"=>"rw3X7VJg8CDnOibniv1jKHTVTGp7pjE4ep6xHpHy0Zp8Xv/0uQd6y5xqq629M2FOOQNoYyOAXH//w5/VoeNEOA==", "work"=>{"title"=>"Progetto1", "author_attributes"=>{"authorName"=>"Autore1", "id"=>"34"}, "client_attributes"=>{"clientName"=>"Cliente4", "id"=>"30"}, "date"=>""}, "commit"=>"update", "id"=>"21"}
  Work Load (0.7ms)  SELECT `works`.* FROM `works` WHERE `works`.`id` = 21 LIMIT 1
  ↳ app/controllers/projects_controller.rb:42:in `update'
  Client Load (0.6ms)  SELECT `clients`.* FROM `clients` WHERE `clients`.`clientName` = 'Cliente4' ORDER BY `clients`.`id` ASC LIMIT 1
  ↳ app/controllers/projects_controller.rb:44:in `update'
  Author Load (0.6ms)  SELECT `authors`.* FROM `authors` WHERE `authors`.`authorName` = 'Autore1' ORDER BY `authors`.`id` ASC LIMIT 1
  ↳ app/controllers/projects_controller.rb:45:in `update'
Completed 404 Not Found in 15ms (ActiveRecord: 1.9ms | Allocations: 3805)



ActiveRecord::RecordNotFound (Couldn't find Client with ID=30 for Work with ID=21):

app/controllers/projects_controller.rb:47:in `update'

Даже если эти записи do существуют в базе данных (с теми идентификаторами, которые вы видите в ошибке) и их внешние ключиправильно хранятся в таблице works (я проверял в mysql).

Я ожидаю достичь того же поведения действия new (которое я описал в начале своего поста).

Как я могу решить это? Спасибо!


Небольшое обновление : если я изменяю first_or_initialize на first_or_create, это создает автора (или клиента), если он не существует, но в то же времяэто все еще дает мне ту же ошибку.

1 Ответ

0 голосов
/ 16 октября 2019

После десятков тестов я, в конце концов, придумал какое-то решение - оно не "изящное" и, вероятно, не самое лучшее, но, по крайней мере, оно работает без перерывов:

 def edit
    @work = Work.find(params[:id])

    if @work.client.nil?
      @work.build_client
    end 

    if @work.author.nil?
      @work.build_author
    end

  end

  def update
    @work = Work.find(params[:id])

    @work.client = Client.where(clientName: work_params["client_attributes"]["clientName"]).first_or_create
    @work.author = Author.where(authorName: work_params["author_attributes"]["authorName"]).first_or_create

    if @work.update(update_params) 
      flash[:notice] = "work: #{@work.title} updated successfully."
      redirect_to(project_path(@work))
    else
      redirect_to new_project_path
    end

  end

private

    def work_params
      params.require(:work).permit(:title, :date, client_attributes: [:id, :clientName], author_attributes: [:id, :authorName])
    end

    def update_params
      params.require(:work).permit(:title, :date)
    end

Будучи таким first_or_initialize гладко работает с save методом, но застревает - по крайней мере, в моем коде - с update, я заменил его на first_or_create.

Однако на этот раз я использую другой закрытый метод update_params, который просто игнорирует :client_attributes и :authors_attributes.

Это приводит к ошибке Unpermitted parameters: :author_attributes, :client_attributes, как и ожидалось, нопо крайней мере, все проходит и обновляется.

Честно говоря, я не совсем уверен, что полностью понял, почему это работает. Но это так.

В любом случае, если у кого-то есть лучшее решение этой проблемы, я полностью готов ее улучшить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...