在Rails 5中,创建了many_to_many关联,同时保存了关系的任何一侧[duplicate]

问题描述 投票:0回答:1

标题可能不是很解释(我尝试过,对不起)。

场景

我具有ComputerSoftware的多对多关系,因此具有联接模型ComputerSoftware。我想在创建新计算机时能够将计算机与当前可用软件列表中的许多软件连接起来。这是一些代码来解释:

class Computer < ApplicationRecord
  has_many :computer_softwares
  has_many :computers, through: :computer_softwares

  accepts_nested_attributes_for :softwares
end

class Software < ApplicationRecord
  has_many :computer_softwares
  has_many :softwares, through: :computer_softwares
end

class ComputerSoftware < ApplicationRecord
  belongs_to :software
  belongs_to :computer
end

我的控制器看起来像这样:

class ComputersController < ApplicationController
  before_action :set_computer, only: %i[show edit update destroy]
  before_action :set_softwares, only: :new

  def index
    @computers = Computer.all
  end

  def show; end

  def new; end

  def edit; end

  def create
    @computer = Computer.new(computer_params)
    # do something to save the associated softwares...
    # params.require(:computer).permit(:softwares) <= unpermitted param

    if @computer.save
      redirect_to computers_path, notice: 'Successfully created.'
    else
      render :new
    end
  end

  def update
    if @computer.update(computer_params)
      redirect_to @computer, notice: 'Successfully updated.'
    else
      render :edit
    end
  end

  def destroy
    @computer.destroy
    redirect_to computers_url, notice: 'Successfully destroyed.'
  end

  private

  def set_computer
    @computer = Computer.find(params[:id])
  end

  def computer_params
    params.require(:computer).permit(:name)
  end

  def set_softwares
    @softwares = Software.all
  end
end

关联正常,我在rails console中进行了测试,一切都很好。但是现在我来创建一个表格,例如Computer

app/views/computers/_form.html.erb

<%= form_with(model: computer, local: true) do |form| %>
  <div>
    <%= form.label :name %>
    <%= form.text_field :name %>
  </div>

  <%= form.collection_check_boxes :softwares, @softwares, :id, :name, include_hidden: false do |field| %>
    <%= field.check_box %>
    <%= field.text %>
  <% end %>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>

我已经尝试过对此进行一些修改,但是由于softwares的原因,我总是会在视图中出现一些错误,或者即使在accepts_nested_attributes_for :softwares模型中设置了Computer的情况下,也不允许在控制器中使用参数。

无奈之下,我选择尝试使复选框完全不属于computer,并仅在控制器中通过关联创建联接。这对于new有用,但随后在edit中失败了。任何帮助,不胜感激。

Edit 1(应jvillian的要求)

我尝试过的强大参数如下:

def computer_params
  required_params.permit(computer_softwares_attributes: [:software_id])
end

def required_params
  params.require(:computer)
end

但是这会导致服务器日志中出现unpermitted params消息(结果是computer_params[:computer_softwares]nil)。在服务器日志中,它看起来如下所示:

Unpermitted parameters: :name, :computer_softwares
<ActionController::Parameters {} permitted: true>

编辑2

[不知道为什么我较早就没想到-但是删除了严格的要求,只是执行params[:computer][:softwares]实际上效果很好。真正剩下的唯一问题是我如何使用强参数来达到相同的结果,否则将很容易受到攻击。

ruby-on-rails ruby ruby-on-rails-5
1个回答
2
投票

您需要允许computer_params中的那些嵌套属性:

def computer_params
  params.require(:computer).permit(:name, software: [:something, :something_else])
end

您想为嵌套软件模型允许的任何字段都必须放在该software键内

© www.soinside.com 2019 - 2024. All rights reserved.