【问题标题】:Nested Attributes With JSON Rails One to Many使用 JSON Rails 一对多的嵌套属性
【发布时间】:2026-01-21 21:15:01
【问题描述】:

我发现了一个nested_attribute 的问题。

team.rb:

class Team < ApplicationRecord
  has_many :players, dependent: :destroy
  accepts_nested_attributes_for :players, allow_destroy: true
end

控制台输出:

Processing by TeamsController#create as JSON
  Parameters: {"team"=>{"id"=>nil, "name"=>"testes",
  "players_attributes"=>[{"id"=>nil, "name"=>"dadada", "_destroy"=>false, "team_id"=>nil}]}}
Unpermitted parameter: id

所以,我忽略了控制器中的 team_id 来创建并将其作为 null 发送,与 player_id 相同。获得许可后,rails 进入控制器的是:

team: {name:'testes team', players_attributes: [{ name: 'testes'}]}

在我看来(可能是我的错误)rails 应该以这种方式提供这种关系。我测试了它删除嵌套属性idteam_id 但不起作用。

轨道返回:

bodyText: "{"players.team":["must exist"]}

控制器:

def create
  @team = Team.create(team_params)

  @team.players.each do |player|
    player.team_id = 1
  end

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

def team_params
  params.require(:team).permit(:name, players_attributes: [:name, :positions, :_destroy])
end

冈比亚拉

@team.players.each do |player|
  player.team_id = 1
end

如果我在保存团队之前对嵌套属性执行此操作,则团队 1 必须存在才能正常工作。如果我只保存团队并且在创建关系之后它也不起作用,只有我设置了 "gambiarra" 解决方案。

如何解决这种关系?如前所述,我的控制器仅过滤嵌套数据的属性。如果我使用 HTML 提交,工作正常,如果我使用 JSON 作为嵌套对象,除非我强制关系在保存之前为我的播放器找到 a team_id 等等,否则它不起作用,等等, rails 将保存并提交正确的播放器,就像我的播放器中没有 team_id 一样。

【问题讨论】:

  • 你的意思是"computer must exists"?另外,我不确定我是否理解您的问题,您能否说明预期的行为是什么?
  • 是的!确切地。我正在与团队和球员一起发展,大声笑,我的错。好吧,问题是 rails 拒绝我添加行,返回一个错误,说我应该在添加扬声器之前有一台计算机,但是这台计算机也是新的,我期待嵌套属性来提供关系。
  • 你能发布你的实际代码吗? computer/teamplayer/speaker 之间的变化具有误导性。这样我们可以更快地发现问题。还有,material.require(:computer).permit(speaker_attributes: [:power]) 中的material 是从哪里来的?
  • 我试图更好地理解重写它的问题,就像我在其他社交媒体中所做的那样,我很抱歉。我将重写所有组件的所有代码。
  • 找到this的回答,看看,我想这也是你的问题。

标签: mysql ruby-on-rails json nested-attributes ruby-on-rails-5.1


【解决方案1】:

您发送的参数结构不正确,rails 需要这样的东西才能使用 嵌套属性

{
  "computer": {
    "speakers_attributes": {
      "0": {
        "power": "1"
      }
    }
  }
}

注意三件事:

  1. computer: null 已删除;您不需要指定computer 属性,因为它的值将使用要创建的新计算机的id 进行设置。

  2. "0": 已添加;由于has_many :speakers 关联,您可以创建多个Speaker(您将使用1: { ... }, 2: { ... },依此类推)。

  3. speaker: 改为speakers_attributes;这就是 rails 识别 嵌套属性 值的方式。

既然已经正确设置了参数,你还需要做两件事:

  1. 确认您的关联设置正确

    class Computer < ApplicationRecord
      has_many :speakers, dependent: :destroy
      accepts_nested_attributes_for :speakers, allow_destroy: true
    end
    
    class Speaker < ApplicationRecord
      belongs_to :computer
    end
    
  2. 正确设置你的控制器

    class ComputersController < ApplicationController
      def new
        @computer = Computer.new
        @computer.speakers.build
      end
    
      def create
        @computer = Computer.create(computer_params)
    
        if @computer.save
          # handle success
        else
          # handle error
        end
      end
    
      # other actions
    
      private
      def computer_params
        params.require(:computer).permit(speakers_attributes: [:power])
      end
    end
    

这里@computer.speakers.build 仅当您将使用表单助手创建嵌套表单时才需要。

【讨论】:

  • 实际上,我正在创建嵌套表单,但又是我的错,我使用的是新的 json,我编辑了帖子,对不起!无论如何,谢谢你。但这似乎无济于事,因为您告诉我如何通过 activerecord 处理。正如我所提到的,我的记录是因为我设置了一个有效数据而创建的。正如我之前的帖子一样,我的模型和一切似乎都很好。对于数字 2,rails 不需要 0:您可以通过 [ 更改它,否则它将不是 JSON,它将是 RAILSON ;D 问题是:如果我使用 rails 按钮,如果我使用 JSON,OK 工作正常通过 webpacker 使用 VUE 变量,不
  • 我的记录被创建,因为我将一个有效数据设置为@computer.player.each do player player.id...(awser 不完整)
  • @AllanFelipeMurara 是的,您可以通过这种方式创建它,但您需要自己添加它(这没关系,如果您的输入要求它);这个答案旨在回应“我期望嵌套属性来提供关系”。我认为它确实如此(是的,使用0:[..])。不管怎样,看来你的问题已经解决了,祝你好运! :)
  • 但问题是,我使用 [] 作为 json 的枚举数。当我更新我的 awnser 时,该对象正在正确提供。正如我所说,问题是在嵌套扬声器中提供计算机 ID。正如我在我的问题中所说的那样,我可以使用 html 表单添加信息,并且只要我将现有 id 添加到 player.team_id ,我就可以使用 JSON。所以我在 5.1 + 使用 JSON 的嵌套属性中遇到了一个问题,现在我提醒可能是 mysql 中的字段类型。我会尝试将其更改为 json。
  • @AllanFelipeMurara 好的,我明白了,看看你更新的问题,你仍在使用computer_id: nil(我假设它是computer而不是team),所以你会得到错误,因为nil 不是有效的 computer_id(不存在)。尝试在不使用 id: nilcomputer_id: nil 的情况下执行相同操作,它应该可以工作。