Ruby on Rails中的嵌套属性无法保存 [英] Nested attributes in Ruby on Rails not saving

查看:59
本文介绍了Ruby on Rails中的嵌套属性无法保存的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我会看下面的答案,但仍然没有找到一个可行的解决方案(不过,鉴于我可能忽略了某些内容的可能性,我将其包括在内作为参考):

I'll preface this by saying I've looked at the following answers and still have not hit a solution that works (however, given the possibility I might have overlooked something, I'm including them for reference):

  • Ruby on Rails - Not saving User - Nested Attributes and Nested Forms
  • Nested Attributes in ruby on rails
  • Ruby on Rails nested attributes not saving into database?
  • Nested attributes not saving in database? Does not display values - Ruby on Rails

问题描述:我有一个带有Block嵌套形式的Cue表单.表单可以正确呈现,并且块可以正确保存,但是提示不会出现在提示表中,即,提交块时提示没有保存.我正在使用Rails 4.2.5.1.我也没有提交任何错误,这使得诊断起来有点困难.

Description of problem: I have a form Block with a nested form for Cue. The form renders correctly and the Block saves correctly, but the Cue does not appear in the Cue table, i.e. the Cue isn't saving when the Block is submitted. I'm using Rails 4.2.5.1. I also don't get any errors on submit, making this a bit difficult to diagnose.

代码:

_form.html.erb-块

_form.html.erb - block

<%= form_for(@block) do |f| %>
  <% if @block.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@block.errors.count, "error") %> prohibited this block from being saved:</h2>

      <ul>
      <% @block.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field hidden">
    <%= f.label :block_code, class: "hidden" %><br>
    <%= f.text_field :block_code, class: "form-control hidden" %>
  </div>
  <div class="field">
    <%= f.label :block_duration %><br>
    <div class="input-group">
      <%= f.number_field :block_duration, class: 'text_field form-control', :step => 'any' %>
      <div class="input-group-addon">seconds</div>
    </div>
  </div>
  <div class="field">
    <label>Does this block have a cue associated with it?</label>
    <input type="radio" name="cue" value="cueYes" data-type="cueYes" data-radio="cue"> Yes
    <input type="radio" name="cue" value="cueNo" data-type="cueNo" data-radio="cue" checked> No
    <div class="field" id="cueYes">
      <%= f.fields_for :cues do |ff| %>
        <div class="field hidden">
          <%= ff.label :cue_code, class: "hidden" %><br>
          <%= ff.text_field :cue_code, class: "hidden" %>
        </div>
        <div class="field">
          <%= ff.label "Cue Type" %><br>
          <%= ff.collection_select(:cue_type_code, CueType.all, :cue_type_code, :cue_type_name, {prompt: "Select a cue type..."}, {class: "form-control"}) %>
        </div>
        <div class="field">
          <%= ff.label "Cue Description" %><br>
          <%= ff.text_area :cue_description, class: "form-control" %>
        </div>
        <div class="field">
          <%= ff.label "Cue Method" %><br>
          <%= ff.collection_select( :cue_method_code, CueMethod.all, :cue_method_code, :cue_method_name, {prompt: "Select a cue method..."}, {class: "form-control"}) %>
        </div>
      <% end %>
    </div>
  </div>
  <div class="field">
    <%= f.label "Location" %><br>
    <%= collection_select :block, :location_code, Location.all, :location_code, :location_name, {prompt: "Select a location..."}, {class: "form-control"} %>
  </div>
  <div class="field">
    <%= f.label "Scene" %><br>
    <%= collection_select :block, :scene_code, Scene.all, :scene_code, :actAndScene, {prompt: "Select a scene..."}, {class: "form-control"} %>
  </div>
  <div class="field">
    <%= f.label "Block Description" %><br>
    <%= f.text_area :block_description, class: "form-control" %>
  </div>
  <div class="actions">
    <%= f.submit "Create Block", class: "btn btn-primary" %>
  </div>
<% end %>

blocks_controller.rb

blocks_controller.rb

class BlocksController < ApplicationController
  before_action :set_block, only: [:show, :edit, :update, :destroy]

  # GET /blocks
  # GET /blocks.json
  def index
    @blocks = Block.all
  end

  # GET /blocks/1
  # GET /blocks/1.json
  def show
  end

  # GET /blocks/new
  def new
    @block = Block.new

    # Set block code as next integer after max block code.
    @block.block_code = (Block.maximum(:block_code).to_i.next).to_s(2)

  end

  # GET /blocks/1/edit
  def edit
  end

  # POST /blocks
  # POST /blocks.json
  def create
    @block = Block.new(block_params)

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

  # PATCH/PUT /blocks/1
  # PATCH/PUT /blocks/1.json
  def update
    respond_to do |format|
      if @block.update(block_params)
        format.html { redirect_to @block, notice: 'Block was successfully updated.' }
        format.json { render :show, status: :ok, location: @block }
      else
        format.html { render :edit }
        format.json { render json: @block.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /blocks/1
  # DELETE /blocks/1.json
  def destroy
    @block.destroy
    respond_to do |format|
      format.html { redirect_to blocks_url, notice: 'Block was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_block
      @block = Block.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def block_params
      params.require(:block).permit(:block_code, :block_duration, :cue_code, :location_code, :scene_code, :block_description, :cues_attributes => [:cue_code, :cue_type_code, :cue_description, :cue_method_name])
    end
end

block.rb

class Block < ActiveRecord::Base
  has_one :cue, -> { where processed: true }
  accepts_nested_attributes_for :cue, allow_destroy: true

end

cue.rb

class Cue < ActiveRecord::Base
  belongs_to :block
end

cues_controller.rb

cues_controller.rb

class CuesController < ApplicationController
  before_action :set_cue, only: [:show, :edit, :update, :destroy]

  # GET /cues
  # GET /cues.json
  def index
    @cues = Cue.all
  end

  # GET /cues/1
  # GET /cues/1.json
  def show
  end

  # GET /cues/new
  def new
    @cue = Cue.new

    # Set cue code as next integer after max cue code.
    @cue.cue_code = (Cue.maximum(:cue_code).to_i.next).to_s(2)
  end

  # GET /cues/1/edit
  def edit
  end

  # POST /cues
  # POST /cues.json
  def create
    @cue = Cue.new(cue_params)

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

  # PATCH/PUT /cues/1
  # PATCH/PUT /cues/1.json
  def update
    respond_to do |format|
      if @cue.update(cue_params)
        format.html { redirect_to @cue, notice: 'Cue was successfully updated.' }
        format.json { render :show, status: :ok, location: @cue }
      else
        format.html { render :edit }
        format.json { render json: @cue.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /cues/1
  # DELETE /cues/1.json
  def destroy
    @cue.destroy
    respond_to do |format|
      format.html { redirect_to cues_url, notice: 'Cue was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_cue
      @cue = Cue.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def cue_params
      params.require(:cue).permit(:cue_code, :cue_type_code, :cue_description, :cue_method_code)
    end
end

如果还有其他需要,请告诉我! (如果格式不好,也请谅解.)

If anything else is needed, please let me know! (Also sorry if the formatting isn't great).

任何帮助深表感谢!!谢谢!

Any help is much appreciated!! Thanks!!

更新1

我当前在blocks_controller.rb中的行if @block.save上收到错误undefined method 'encoding' for 7:Fixnum(上方).我已根据IngoAlbers(如下)给出的答案和找到的答案更改了以下内容这里.

I'm currently getting the error undefined method 'encoding' for 7:Fixnum on the line if @block.save in blocks_controller.rb (above). I have changed the following things based on the answer given by IngoAlbers (below) and the answer found here.

我更改了以下内容:

blocks_controller.rb

blocks_controller.rb

def block_params
  params.require(:block).permit(:block_code, :block_duration, :cue_code, :location_code, :scene_code, :block_description, :cue_attributes => [:id, :cue_code, :cue_type_code, :cue_description, :cue_method_code])
end

_form.html.erb-块

_form.html.erb - blocks

<%= f.fields_for :cue, @block.build_cue do |ff| %>

block.rb

class Block < ActiveRecord::Base
  has_one :cue
  accepts_nested_attributes_for :cue, allow_destroy: true

end

非常感谢您提供的帮助!我想我真的很亲密!

Thanks so much for the help so far! I think I'm really close!

更新2

因此,我已将block_id作为属性添加到Cue并运行以下两个迁移:

So I've added block_id as an attribute to Cue and run the following two migrations:

class AddBlockIdToCues < ActiveRecord::Migration
  def self.up
    add_column :cues, :block_id, :binary
  end

  def self.down
    remove_column :cues, :block_id
  end
end


class AddBelongsToToCues < ActiveRecord::Migration
  def change
    add_reference :cues, :blocks, index: true
    add_foreign_key :cues, :blocks
  end
end

blocks_controller.rbif @block.save行上仍然出现错误undefined method 'encoding' for 7:Fixnum.

I'm still getting the error undefined method 'encoding' for 7:Fixnum on the line if @block.save in the blocks_controller.rb.

推荐答案

问题应该出在您的fields_for中.可能应该是:

The problem should be in your fields_for. It should probably be:

<%= f.fields_for :cue do |ff| %>

不是cues,因为它只有一个.然后,您需要构建提示.可以在控制器中或直接在视图中完成,例如:

Not cues since it is only one. Then you need to build the cue. This can be done either in controller or in the view directly, for example like this:

<%= f.fields_for :cue, @block.build_cue do |ff| %>

然后在块参数中,还需要将其更改为cue_attributes,并允许id.

In your block params you then also need to change it to cue_attributes, and also allow id.

def block_params
  params.require(:block).permit(:block_code, :block_duration, :cue_code, :location_code, :scene_code, :block_description, :cue_attributes => [:id, :cue_code, :cue_type_code, :cue_description, :cue_method_name])
end

您还可以在此处阅读更多信息:

You can also read a lot more information here:

http://guides.rubyonrails.org/form_helpers.html#nested-forms

关于第二次更新:

您的第一次迁移将添加类型为binary的列block_id.绝对应该是integer.就是说,您甚至根本不需要第一次迁移,因为如果将add_reference中的blocks更改为block,则第二次迁移将正确处理所有迁移.它应该看起来像这样:

Your first migration adds a column block_id of type binary. It should definitely be integer instead. That said, you don't even need the first migration at all, because your second migration will handle all of it correctly, if you change blocks to block in add_reference. It should look like this:

class AddBelongsToToCues < ActiveRecord::Migration
  def change
    add_reference :cues, :block, index: true
    add_foreign_key :cues, :blocks
  end
end

add_reference需要添加对一个block的引用,而不是多个.然后,这将为您创建合适的列.

The add_reference needs to add a reference to one block not multiple. This will then create the right column for you.

另请参见: http://api.rubyonrails .org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_reference

这篇关于Ruby on Rails中的嵌套属性无法保存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆