代码之家  ›  专栏  ›  技术社区  ›  user3684314

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

  •  2
  • user3684314  · 技术社区  · 9 年前

    我先说,我已经看过以下答案,但仍然没有找到有效的解决方案(不过,考虑到我可能忽略了一些东西,我将把它们包括在内以供参考):

    问题描述:我有一个表单块,其中包含Cue的嵌套表单。表单渲染正确,块保存正确,但提示未出现在提示表中,即提交块时提示未保存。我使用的是Rails 4.2.5.1。我在提交时也没有收到任何错误,这使得诊断有点困难。

    代码:

    _表单.html。erb块

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

    块_控制器.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
    

    块.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
    

    提示控制器.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.save 在里面 blocks_controller.rb (见上文)。我根据以下人员给出的答案更改了以下内容 IngoAlbers (下面)和找到的答案 here .

    我更改了以下内容:

    块_控制器.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
    

    _表单.html。erb-块

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

    块.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
    

    我还是有错误 未定义7的方法“encoding”:Fixnum 在线上 如果@block.save 块_控制器.rb .

    1 回复  |  直到 8 年前
        1
  •  2
  •   IngoAlbers    9 年前

    问题应该在你的 fields_for 。它可能是:

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

    cues 因为它只是一个。然后你需要建立线索。这可以在控制器或视图中直接完成,例如:

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

    在块参数中,您还需要将其更改为 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 block 在里面 add_reference 。应如下所示:

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

    这个 添加引用(_R) 需要添加对一个的引用 不是多重的。这将为您创建正确的列。

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