Ruby on Rails中的嵌套属性无法保存 [英] Nested attributes in Ruby on Rails not saving
问题描述
首先,我会看下面的答案,但仍然没有找到一个可行的解决方案(不过,鉴于我可能忽略了某些内容的可能性,我将其包括在内作为参考):
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-不保存用户-嵌套属性和嵌套表单
- 红宝石在轨道上的嵌套属性
- Ruby on Rails嵌套属性未保存到数据库中吗?
- 没有嵌套的属性保存在数据库中?不显示值-Ruby on Rails
- 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.rb
的if @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.
这篇关于Ruby on Rails中的嵌套属性无法保存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!