Rails 6 вложенных ресурсов с сильными параметрами - PullRequest
2 голосов
/ 14 марта 2020

У меня есть вложенные ресурсы в моем приложении Rails, в основном Project имеет Targets, и я подумал, что самый простой способ go о создании отношений - это сделать это в моих маршрутах. Rb:

resource :projects do
  resource :targets
end

Мои модели в значительной степени соответствуют этому:

- Project.rb
class Project < ApplicationRecord
  has_many :targets
end

- Target.rb
class Target < ApplicationRecord
  has_one :project
end

Запуск rake routes показывает мне то, что я ожидал:

project_targets GET    /projects/:project_id/targets(.:format)                                                  targets#index
                                      POST   /projects/:project_id/targets(.:format)                                                  targets#create
                   new_project_target GET    /projects/:project_id/targets/new(.:format)                                              targets#new
                  edit_project_target GET    /projects/:project_id/targets/:id/edit(.:format)                                         targets#edit
                       project_target GET    /projects/:project_id/targets/:id(.:format)                                              targets#show
                                      PATCH  /projects/:project_id/targets/:id(.:format)                                              targets#update
                                      PUT    /projects/:project_id/targets/:id(.:format)                                              targets#update
                                      DELETE /projects/:project_id/targets/:id(.:format)                                              targets#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

После того, как я это сделал, мой создание / редактирование форм больше не работает для target, поэтому мне пришлось настроить первую строку form_for из:

<%= form_for @target do |f| %>

to

<%= form_for @target, url: project_targets_path do |f| %>

Обратите внимание, что мне пришлось явно объявить URL

Метод создания в Target контроллере довольно простой c:

def create
  @target = Target.create(target_params)
  if @target.valid?
    redirect_to project_target_path(id: @target.id)
  else
    flash[:errors] = @target.errors.full_messages
    redirect_to new
  end
end

Моя попытка создать цель успешна, но для цели не назначено project_id В соответствии со схемой БД:

create_table :targets do |t|
  t.string :domain
  t.boolean :investigated, default: false
  t.boolean :research, default: false
  t.integer :project_id
  t.timestamps
end

Это то, что я вижу в журналах, ясно, что project_id передается как часть URL-адреса, но не ассоциируется с новой целью при создании.

Started POST "/projects/1/targets" for ::1 at 2020-03-13 19:19:57 -0400
Processing by TargetsController#create as HTML
  Parameters: {"authenticity_token"=>"jLzQmpsxMRW4z66WguFVwZcLnMxFJYIy86EDfru6fIhysWDU/fd6yq5HV2uv1Z3TICGQSAXZDll66DwizReWaQ==", "target"=>{"domain"=>"2-test.com"}, "commit"=>"Create", "project_id"=>"1"}
   (0.1ms)  begin transaction
  ↳ app/controllers/targets_controller.rb:11:in `create'
  Target Create (0.8ms)  INSERT INTO "targets" ("domain", "created_at", "updated_at") VALUES (?, ?, ?)  [["domain", "2-test.com"], ["created_at", "2020-03-13 23:19:57.097233"], ["updated_at", "2020-03-13 23:19:57.097233"]]
  ↳ app/controllers/targets_controller.rb:11:in `create'
   (1.1ms)  commit transaction
  ↳ app/controllers/targets_controller.rb:11:in `create'

Мои настройки неверны? Как я могу это исправить, чтобы при создании новой цели включался project_id? Я хотел бы сохранить этот RESTful и не пропускать скрытое поле, если в нем есть project_id.

1 Ответ

5 голосов
/ 14 марта 2020

Установите форму как:

<%= form_for [@project, @target] do |f| %>

Хотя вы можете явно передать URL:

<%= form_for @target, url: project_targets_path(@project) do |f| %>

Это нарушит действия edit и update, если вы разделяют форму частично, так как при обновлении атрибут действия должен указывать на /projects/:project_id/targets/:id. Предпочитайте соглашение по конфигурации.

Ваш метод создания также во многих отношениях нарушен.

class TargetsController < ApplicationController
  before_action :set_project
  before_action :set_target, except: [:new, :index]

  # POST /projects/1/targets
  def create
    # building the new record off the parent sets the project_id
    @target = @project.targets.new(target_params)
    if @target.save
      redirect_to [@project, @target] 
    else
      flash[:errors] = @target.errors.full_messages
      # When a record is invalid always render - never redirect.
      render :new
    end
  end

  private
  def set_project
    @project = Project.find(params[:project_id])
  end
  # ...
end

if @project.valid? просто проверяет, прошли ли проверки приложения, а не, если запись действительно сохранялась в базу данных. Проверка возвращаемого значения @target.save или @target.persisted? делает.

Обратите внимание, что :project_id не должен включаться в белый список параметров, так как он проходит через URL, а не при массовом назначении. Вложенность маршрутов действительно не имеет ничего общего с сильными параметрами.

Вам также следует прочитать поверхностное вложение , поскольку вам, скорее всего, не нужно вкладывать маршруты участников, и это значительно снижает сложность.

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