2016-03-22 8 views
2

Я предоставлю это, сказав, что я рассмотрел следующие ответы и до сих пор не ударил решение, которое работает (однако, учитывая возможность, я мог бы что-то упустить, я в том числе их для справки):Вложенные атрибуты в Ruby on Rails не сохраняются

Описание проблемы: У меня есть форма Block с вложенной формой для Cue. Форма корректно отобразится, и блок сохранит правильно, но Cue не отображается в таблице Cue, т. Е. Cue не сохраняется при отправке блока. Я использую Rails 4.2.5.1. Я также не получаю никаких ошибок при отправке, что затрудняет диагностику.

Код:

_form.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 %> 

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

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 

Если что-то еще нужно, пожалуйста, дайте мне знать! (Также жаль, если форматирование не очень велико).

Любая помощь очень ценится !! Благодаря!!

UPDATE 1

В настоящее время я получаю ошибку undefined method 'encoding' for 7:Fixnum на линии if @block.save в blocks_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 - блоки

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

Большое спасибо за h elp до сих пор! Я думаю, что я действительно рядом!

UPDATE 2

Так я добавил block_id как атрибут перемотать и запустить следующие две миграции:

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.save в blocks_controller.rb.

+0

Вы пытались создать объект кием в консоли рельсы? Можете ли вы использовать некоторую проверку для '@ cue', чтобы помочь с отладкой , например' validates: cue_description, presence: true' и посмотреть, можете ли вы отправить форму. – Aloalo

+0

Прошу извинить мое невежество в этом ... Поэтому я добавил вашу линию к модели Cue под 'own_to' и попробовал добавить еще один блок. Параметры передаются ... Я вижу '' cues '=> {"cue_code" => "", "cue_type_code" => "1" ... "cue_method_code" => ""} ', а затем после этого 'Неперечисленный параметр: cues'? – user3684314

ответ

2

Проблема должна быть в вашем fields_for. Это, вероятно, следует:

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

Не cues, так как это только один. Затем вам нужно построить кий. Это может быть сделано либо в контроллере или в представлении непосредственно, например, так:

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

В вашем блоке PARAMS вы затем также необходимо изменить его 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 

В add_reference необходимо добавить ссылку на один block не множественным. Затем вы создадите для вас правый столбец.

Смотрите также: http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_reference

+0

Большое спасибо! Я думаю, что я приближаюсь к ответу ... Итак, теперь я выполнил все ваши изменения, и я получаю «ActiveRecord :: UnknownAttributeError в блоках # новый», в частности «неизвестный атрибут block_id» для Cue.' , Трассировка показывает, что она находится в строке '<% = f.fields_for: cue, @ block.build_cue do | ff | %> '. Я думаю, что это ссылка на часть «build_cue» ... – user3684314

+0

Это, вероятно, означает, что у вас нет столбца 'block_id' в вашей таблице' cues', которая используется ассоциацией 'belongs_to'. См. Http://guides.rubyonrails.org/association_basics.html#the-belongs-to-association о том, как должны выглядеть таблицы, и миграции для создания желаемой структуры. – IngoAlbers

+0

Я сделал это, и я все еще получаю ошибки ...Я отправлю второе обновление, поскольку это все еще происходит. – user3684314

Смежные вопросы