ruby-on-rails - Ruby on Rails 中的嵌套属性未保存

标签 ruby-on-rails forms ruby-on-rails-4 nested-attributes

我会在序言中说,我已经查看了以下答案,但仍然没有找到有效的解决方案(但是,考虑到我可能忽略了某些内容,我将它们包括在内以供引用):

问题描述:我有一个带有 Cue 嵌套表单的表单 block 。表单正确呈现并且 block 正确保存,但 Cue 未出现在 Cue 表中,即提交 block 时 Cue 未保存。我正在使用 Rails 4.2.5.1。我在提交时也没有收到任何错误,这使得诊断有点困难。

代码:

_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

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

提示.rb

class Cue < ActiveRecord::Base
  belongs_to :block
end

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

如果还有什么需要,请告诉我! (如果格式不好,也很抱歉)。

非常感谢任何帮助!谢谢!!

更新1

我当前收到错误 undefined method 'encoding' for 7:Fixnum上线if @block.saveblocks_controller.rb (多于)。我根据 IngoAlbers 给出的答案更改了以下内容(如下)并找到答案 here .

我更改了以下内容:

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 - block

<%= 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

非常感谢您迄今为止的帮助!我想我已经很接近了!

更新2

所以我添加了block_id作为 Cue 的属性并运行以下两个迁移:

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

我仍然收到错误 undefined method 'encoding' for 7:Fixnum上线if @block.saveblocks_controller.rb .

最佳答案

问题应该出在你的 fields_for 上。大概应该是:

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

不是cues因为它只有一个。然后你需要构建提示。这可以在 Controller 中或直接在 View 中完成,例如如下所示:

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

在您的 block 参数中,您还需要将其更改为 cue_attributes ,并且还允许 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

您还可以在这里阅读更多信息:

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

关于您的第二次更新:

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

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

add_reference需要添加对 block 的引用不是多个。然后,这将为您创建正确的列。

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

关于ruby-on-rails - Ruby on Rails 中的嵌套属性未保存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36145305/

相关文章:

ruby-on-rails - 多态 has_and_belongs_to_many

ruby-on-rails - 如何使用github repo作为CDN服务器上传 Assets 文件?

javascript - 如何将 onfocus 事件监听器添加到输入字段以更改标签的样式

css - Rails 4 - 在生产中使用 CDN

ios - Rails 4 iOS 身份验证和授权

ruby-on-rails - 在 Rails 4 中格式化我的 JSON 输出

ruby-on-rails - 安装 Nokogiri gem 时出错

ruby-on-rails - 如何自定义collection_check_boxes的id

java - 如何在 Liferay 7 表单中插入屏幕名称?

php - 让我的 JavaScript 文本编辑器提交