嵌套表单中的嵌套表单 - Cocoon Gem:第 3 级 child 不保存 - Rails 5
Nested form inside of a nested form - Cocoon Gem: 3rd level child doesn't save - Rails 5
花了几个小时试图研究解决方案,发现了一些非常相似的问题 like this one, or ,尽管所有建议的修复都没有解决我的问题:
正在尝试使用 Cocoon Gem 在嵌套表单内部构建嵌套表单,但第 3 级 child 不会保存到数据库中。
模型结构非常简单,只有 "has_many / belongs_to" 个关系:
一个文本有很多引用。一个引用有很多评论。
实现中的动态 UI 交互有效,添加和删除字段有效,不幸的是,尽管只保存文本和引号,而不保存评论。没有显示错误。
表格如下:
_text_form.html.erb
<%= form_for(@text, html: { multipart: true }) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_field :title, placeholder: "Enter Title" %>
</div>
<div>
<h3>Quotes:</h3>
<div id="quotes">
<%= f.fields_for :quotes do |quote| %>
<%= render 'quote_fields', f: quote %>
<% end %>
<div class="links">
<%= link_to_add_association 'add quote', f, :quotes, class: "btn btn-default" %>
</div>
</div>
</div>
<%= f.submit %>
<% end %>
_quote_fields.html.erb
<div class="nested-fields">
<%= f.text_area :content, placeholder: "Compose new quote..." %>
<span class="picture">
<%= f.file_field :picture, accept: 'image/jpeg,image/gif,image/png' %>
</span>
<div>
<h3>Comments:</h3>
<div id="comments">
<%= f.fields_for :comments do |comment| %>
<%= render 'comment_fields', f: comment %>
<% end %>
<div class="links">
<%= link_to_add_association 'add comment', f, :comments, class: "btn btn-default" %>
</div>
</div>
</div>
<div class="links">
<%= link_to_remove_association "remove quote", f, class: "btn btn-default" %>
</div>
</div>
<script type="text/javascript">
$('#quote_picture').bind('change', function() {
var size_in_megabytes = this.files[0].size/1024/1024;
if (size_in_megabytes > 2) {
alert('Maximum file size is 2MB. Please choose a smaller file.');
}
});
</script>
_comment_fields.html.erb
<div class="nested-fields">
<%= f.text_area :bodycomment, placeholder: "Write a comment..." %>
<%= link_to_remove_association "remove comment", f, class: "btn btn-default" %>
</div>
以下是模型:
text.rb
class Text < ApplicationRecord
belongs_to :user, inverse_of: :texts
has_many :quotes, dependent: :destroy, inverse_of: :text
has_many :comments, :through => :quotes
accepts_nested_attributes_for :quotes, reject_if: :all_blank, allow_destroy: true
accepts_nested_attributes_for :comments, reject_if: :all_blank, allow_destroy: true
default_scope -> { order(created_at: :desc) }
mount_uploader :coverimage, CoverimageUploader
validates :user_id, presence: true
validates :title, presence: true
validate :coverimage_size
private
# Validates the size of an uploaded picture.
def coverimage_size
if coverimage.size > 5.megabytes
errors.add(:coverimage, "should be less than 5MB")
end
end
end
quote.rb
class Quote < ApplicationRecord
belongs_to :text, inverse_of: :quotes
has_many :comments, dependent: :destroy, inverse_of: :quote
accepts_nested_attributes_for :comments, reject_if: :all_blank, allow_destroy: true
mount_uploader :picture, PictureUploader
validates :content, presence: true, length: { maximum: 350 }
validate :picture_size
private
#Validates size of image upload
def picture_size
if picture.size > 2.megabytes
errors.add(:picture, "should be less than 2MB")
end
end
end
comment.rb
class Comment < ApplicationRecord
belongs_to :quote, inverse_of: :comments
validates :quote_id, presence: true
validates :bodycomment, presence: true
end
这里是控制器:
quotes_controller.rb
class QuotesController < ApplicationController
before_action :logged_in_user, only: [:create, :destroy]
before_action :correct_user, only: :destroy
def show
end
def create
@quote = current_user.quotes.build(quote_params)
if @quote.save
flash[:success] = "Quote created!"
redirect_to root_url
else
@feed_items = []
render 'static_pages/home'
end
end
def destroy
@quote.destroy
flash[:success] = "Quote deleted"
redirect_to request.referrer || root_url
end
private
def quote_params
params.require(:quote).permit(:content, :picture, comments_attributes: [:id, :bodycomment
, :_destroy])
end
def correct_user
@quote = current_user.quotes.find_by(id: params[:id])
redirect_to root_url if @quote.nil?
end
end
comments_controller.rb
class CommentsController < ApplicationController
before_action :logged_in_user, only: [:create, :edit, :update, :destroy]
before_action :correct_user, only: :destroy
def show
end
def create
@comment = current_user.comments.build(comment_params)
if @comment.save
flash[:success] = "Comment created!"
redirect_to root_url
else
@feed_items = []
render 'static_pages/home'
end
end
def destroy
@comment.destroy
flash[:success] = "Comment deleted"
redirect_to request.referrer || root_url
end
private
def comment_params
params.require(:comment).permit(:bodycomment)
end
def correct_user
@comment = current_user.comments.find_by(id: params[:id])
redirect_to root_url if @comment.nil?
end
end
想知道是不是 javascript 问题...
非常感谢您对此进行调查。非常感谢,感谢您的帮助。
编辑
这里是texts_controller.rb
class TextsController < ApplicationController
before_action :logged_in_user, only: [:create, :edit, :update, :destroy]
before_action :correct_user, only: :destroy
before_action :find_text, only: [:show, :edit, :update, :destroy]
def show
end
def new
@text = current_user.texts.build
end
def create
@text = current_user.texts.build(text_params)
if @text.save
flash[:success] = "Text created!"
render 'show'
else
render 'static_pages/home'
end
end
def edit
end
def update
if @text.update(text_params)
redirect_to root_url
else
render 'edit'
end
end
def destroy
@text.destroy
flash[:success] = "Text deleted"
redirect_to request.referrer || root_url
end
private
def text_params
params.require(:text).permit(:url, :title, :coverimage,
:publication, :author, :summary, quotes_attributes: [:id, :content, :picture, :_destroy], comments_attributes: [:id, :bodycomment, :_destroy])
end
def find_text
@text = Text.find(params[:id])
end
def correct_user
@user = User.find(params[:id])
redirect_to(root_url) unless current_user?(@user)
end
end
以下是我在保存表单字段后获得的一些日志信息:
--- !ruby/object:ActionController::Parameters
parameters: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
utf8: "✓"
authenticity_token: NQLh7TwlhfbV4ez91HGMyYZK6YYYiLXhHG/cAhrAsRylIAuFFhjnKX0vEO8ZIVbsxGES3byBgUMz21aSOlGiqw==
text: !ruby/object:ActionController::Parameters
parameters: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
title: Title of the Book
quotes_attributes: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
'1490626822148': !ruby/hash:ActiveSupport::HashWithIndifferentAccess
content: This is a quote from the book.
_destroy: 'false'
comments_attributes: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
'1490626833771': !ruby/hash:ActiveSupport::HashWithIndifferentAccess
bodycomment: Here is a comment on the quote of the book.
_destroy: 'false'
permitted: false
commit: Create Text
controller: texts
action: create
permitted: false
这里是终端的日志文件:
Started POST "/texts" for ::1 at 2017-03-27 17:00:51 +0200
Processing by TextsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"NQLh7TwlhfbV4ez91HGMyYZK6YYYiLXhHG/cAhrAsRylIAuFFhjnKX0vEO8ZIVbsxGES3byBgUMz21aSOlGiqw==", "text"=>{"title"=>"Title of the Book", "publication"=>"", "author"=>"", "url"=>"", "summary"=>"", "quotes_attributes"=>{"1490626822148"=>{"content"=>"This is a quote from the book.", "_destroy"=>"false", "comments_attributes"=>{"1490626833771"=>{"bodycomment"=>"Here is a comment on the quote of the book.", "_destroy"=>"false"}}}}}, "commit"=>"Create Text"}
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
Unpermitted parameter: comments_attributes
(0.1ms) begin transaction
SQL (0.7ms) INSERT INTO "texts" ("user_id", "url", "title", "publication", "author", "summary", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?) [["user_id", 1], ["url", ""], ["title", "Title of the Book"], ["created_at", 2017-03-27 15:00:51 UTC], ["updated_at", 2017-03-27 15:00:51 UTC]]
SQL (0.4ms) INSERT INTO "quotes" ("content", "created_at", "updated_at", "text_id") VALUES (?, ?, ?, ?) [["content", "This is a quote from the book."], ["created_at", 2017-03-27 15:00:51 UTC], ["updated_at", 2017-03-27 15:00:51 UTC], ["text_id", 366]]
(1.3ms) commit transaction
Rendering texts/show.html.erb within layouts/application
Quote Load (0.2ms) SELECT "quotes".* FROM "quotes" WHERE "quotes"."text_id" = ? [["text_id", 366]]
Rendered texts/show.html.erb within layouts/application (5.8ms)
Rendered layouts/_shim.html.erb (0.5ms)
Rendered layouts/_header.html.erb (1.4ms)
Rendered layouts/_footer.html.erb (1.8ms)
Completed 200 OK in 127ms (Views: 100.1ms | ActiveRecord: 3.1ms)
- 型号...
text.rb
...我不得不输入 accepts_nested_attributes_for :comments
...除了已经发布的
TextController
...您的嵌套允许参数需要出现在这里,.permit(:content, :picture, quotes_attributes: [:id, :content, :picture, :_destroy, comments_attributes: [:id, :bodycomment, :_destroy]])
我可能把变量名去掉了一点(尤其是你没有列出的 TextController),但基本上,看起来你正试图通过其他控制器继承嵌套——当唯一的控制器被调用时是文本控制器。
可以肯定的是,在第二个控制台中放置 tail -f log/<logname>
或在执行 save/update 时查看终端控制台以观察许可问题。
如果还有问题,请告诉我!
...基于新控制器的更新
控制器需要调整(您现在有一个']'放错了地方)。
params.require(:text).permit(:url, :title, :coverimage,
:publication, :author, :summary, quotes_attributes: [:id, :content, :picture, :_destroy, comments_attributes: [:id, :bodycomment, :_destroy]])
在您也修复模型之前,这将不起作用...
accepts_nested_attributes_for :comments
花了几个小时试图研究解决方案,发现了一些非常相似的问题 like this one, or
正在尝试使用 Cocoon Gem 在嵌套表单内部构建嵌套表单,但第 3 级 child 不会保存到数据库中。
模型结构非常简单,只有 "has_many / belongs_to" 个关系:
一个文本有很多引用。一个引用有很多评论。
实现中的动态 UI 交互有效,添加和删除字段有效,不幸的是,尽管只保存文本和引号,而不保存评论。没有显示错误。
表格如下:
_text_form.html.erb
<%= form_for(@text, html: { multipart: true }) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_field :title, placeholder: "Enter Title" %>
</div>
<div>
<h3>Quotes:</h3>
<div id="quotes">
<%= f.fields_for :quotes do |quote| %>
<%= render 'quote_fields', f: quote %>
<% end %>
<div class="links">
<%= link_to_add_association 'add quote', f, :quotes, class: "btn btn-default" %>
</div>
</div>
</div>
<%= f.submit %>
<% end %>
_quote_fields.html.erb
<div class="nested-fields">
<%= f.text_area :content, placeholder: "Compose new quote..." %>
<span class="picture">
<%= f.file_field :picture, accept: 'image/jpeg,image/gif,image/png' %>
</span>
<div>
<h3>Comments:</h3>
<div id="comments">
<%= f.fields_for :comments do |comment| %>
<%= render 'comment_fields', f: comment %>
<% end %>
<div class="links">
<%= link_to_add_association 'add comment', f, :comments, class: "btn btn-default" %>
</div>
</div>
</div>
<div class="links">
<%= link_to_remove_association "remove quote", f, class: "btn btn-default" %>
</div>
</div>
<script type="text/javascript">
$('#quote_picture').bind('change', function() {
var size_in_megabytes = this.files[0].size/1024/1024;
if (size_in_megabytes > 2) {
alert('Maximum file size is 2MB. Please choose a smaller file.');
}
});
</script>
_comment_fields.html.erb
<div class="nested-fields">
<%= f.text_area :bodycomment, placeholder: "Write a comment..." %>
<%= link_to_remove_association "remove comment", f, class: "btn btn-default" %>
</div>
以下是模型:
text.rb
class Text < ApplicationRecord
belongs_to :user, inverse_of: :texts
has_many :quotes, dependent: :destroy, inverse_of: :text
has_many :comments, :through => :quotes
accepts_nested_attributes_for :quotes, reject_if: :all_blank, allow_destroy: true
accepts_nested_attributes_for :comments, reject_if: :all_blank, allow_destroy: true
default_scope -> { order(created_at: :desc) }
mount_uploader :coverimage, CoverimageUploader
validates :user_id, presence: true
validates :title, presence: true
validate :coverimage_size
private
# Validates the size of an uploaded picture.
def coverimage_size
if coverimage.size > 5.megabytes
errors.add(:coverimage, "should be less than 5MB")
end
end
end
quote.rb
class Quote < ApplicationRecord
belongs_to :text, inverse_of: :quotes
has_many :comments, dependent: :destroy, inverse_of: :quote
accepts_nested_attributes_for :comments, reject_if: :all_blank, allow_destroy: true
mount_uploader :picture, PictureUploader
validates :content, presence: true, length: { maximum: 350 }
validate :picture_size
private
#Validates size of image upload
def picture_size
if picture.size > 2.megabytes
errors.add(:picture, "should be less than 2MB")
end
end
end
comment.rb
class Comment < ApplicationRecord
belongs_to :quote, inverse_of: :comments
validates :quote_id, presence: true
validates :bodycomment, presence: true
end
这里是控制器:
quotes_controller.rb
class QuotesController < ApplicationController
before_action :logged_in_user, only: [:create, :destroy]
before_action :correct_user, only: :destroy
def show
end
def create
@quote = current_user.quotes.build(quote_params)
if @quote.save
flash[:success] = "Quote created!"
redirect_to root_url
else
@feed_items = []
render 'static_pages/home'
end
end
def destroy
@quote.destroy
flash[:success] = "Quote deleted"
redirect_to request.referrer || root_url
end
private
def quote_params
params.require(:quote).permit(:content, :picture, comments_attributes: [:id, :bodycomment
, :_destroy])
end
def correct_user
@quote = current_user.quotes.find_by(id: params[:id])
redirect_to root_url if @quote.nil?
end
end
comments_controller.rb
class CommentsController < ApplicationController
before_action :logged_in_user, only: [:create, :edit, :update, :destroy]
before_action :correct_user, only: :destroy
def show
end
def create
@comment = current_user.comments.build(comment_params)
if @comment.save
flash[:success] = "Comment created!"
redirect_to root_url
else
@feed_items = []
render 'static_pages/home'
end
end
def destroy
@comment.destroy
flash[:success] = "Comment deleted"
redirect_to request.referrer || root_url
end
private
def comment_params
params.require(:comment).permit(:bodycomment)
end
def correct_user
@comment = current_user.comments.find_by(id: params[:id])
redirect_to root_url if @comment.nil?
end
end
想知道是不是 javascript 问题...
非常感谢您对此进行调查。非常感谢,感谢您的帮助。
编辑
这里是texts_controller.rb
class TextsController < ApplicationController
before_action :logged_in_user, only: [:create, :edit, :update, :destroy]
before_action :correct_user, only: :destroy
before_action :find_text, only: [:show, :edit, :update, :destroy]
def show
end
def new
@text = current_user.texts.build
end
def create
@text = current_user.texts.build(text_params)
if @text.save
flash[:success] = "Text created!"
render 'show'
else
render 'static_pages/home'
end
end
def edit
end
def update
if @text.update(text_params)
redirect_to root_url
else
render 'edit'
end
end
def destroy
@text.destroy
flash[:success] = "Text deleted"
redirect_to request.referrer || root_url
end
private
def text_params
params.require(:text).permit(:url, :title, :coverimage,
:publication, :author, :summary, quotes_attributes: [:id, :content, :picture, :_destroy], comments_attributes: [:id, :bodycomment, :_destroy])
end
def find_text
@text = Text.find(params[:id])
end
def correct_user
@user = User.find(params[:id])
redirect_to(root_url) unless current_user?(@user)
end
end
以下是我在保存表单字段后获得的一些日志信息:
--- !ruby/object:ActionController::Parameters
parameters: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
utf8: "✓"
authenticity_token: NQLh7TwlhfbV4ez91HGMyYZK6YYYiLXhHG/cAhrAsRylIAuFFhjnKX0vEO8ZIVbsxGES3byBgUMz21aSOlGiqw==
text: !ruby/object:ActionController::Parameters
parameters: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
title: Title of the Book
quotes_attributes: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
'1490626822148': !ruby/hash:ActiveSupport::HashWithIndifferentAccess
content: This is a quote from the book.
_destroy: 'false'
comments_attributes: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
'1490626833771': !ruby/hash:ActiveSupport::HashWithIndifferentAccess
bodycomment: Here is a comment on the quote of the book.
_destroy: 'false'
permitted: false
commit: Create Text
controller: texts
action: create
permitted: false
这里是终端的日志文件:
Started POST "/texts" for ::1 at 2017-03-27 17:00:51 +0200
Processing by TextsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"NQLh7TwlhfbV4ez91HGMyYZK6YYYiLXhHG/cAhrAsRylIAuFFhjnKX0vEO8ZIVbsxGES3byBgUMz21aSOlGiqw==", "text"=>{"title"=>"Title of the Book", "publication"=>"", "author"=>"", "url"=>"", "summary"=>"", "quotes_attributes"=>{"1490626822148"=>{"content"=>"This is a quote from the book.", "_destroy"=>"false", "comments_attributes"=>{"1490626833771"=>{"bodycomment"=>"Here is a comment on the quote of the book.", "_destroy"=>"false"}}}}}, "commit"=>"Create Text"}
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
Unpermitted parameter: comments_attributes
(0.1ms) begin transaction
SQL (0.7ms) INSERT INTO "texts" ("user_id", "url", "title", "publication", "author", "summary", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?) [["user_id", 1], ["url", ""], ["title", "Title of the Book"], ["created_at", 2017-03-27 15:00:51 UTC], ["updated_at", 2017-03-27 15:00:51 UTC]]
SQL (0.4ms) INSERT INTO "quotes" ("content", "created_at", "updated_at", "text_id") VALUES (?, ?, ?, ?) [["content", "This is a quote from the book."], ["created_at", 2017-03-27 15:00:51 UTC], ["updated_at", 2017-03-27 15:00:51 UTC], ["text_id", 366]]
(1.3ms) commit transaction
Rendering texts/show.html.erb within layouts/application
Quote Load (0.2ms) SELECT "quotes".* FROM "quotes" WHERE "quotes"."text_id" = ? [["text_id", 366]]
Rendered texts/show.html.erb within layouts/application (5.8ms)
Rendered layouts/_shim.html.erb (0.5ms)
Rendered layouts/_header.html.erb (1.4ms)
Rendered layouts/_footer.html.erb (1.8ms)
Completed 200 OK in 127ms (Views: 100.1ms | ActiveRecord: 3.1ms)
- 型号...
text.rb
...我不得不输入accepts_nested_attributes_for :comments
...除了已经发布的 TextController
...您的嵌套允许参数需要出现在这里,.permit(:content, :picture, quotes_attributes: [:id, :content, :picture, :_destroy, comments_attributes: [:id, :bodycomment, :_destroy]])
我可能把变量名去掉了一点(尤其是你没有列出的 TextController),但基本上,看起来你正试图通过其他控制器继承嵌套——当唯一的控制器被调用时是文本控制器。
可以肯定的是,在第二个控制台中放置 tail -f log/<logname>
或在执行 save/update 时查看终端控制台以观察许可问题。
如果还有问题,请告诉我!
...基于新控制器的更新
控制器需要调整(您现在有一个']'放错了地方)。
params.require(:text).permit(:url, :title, :coverimage,
:publication, :author, :summary, quotes_attributes: [:id, :content, :picture, :_destroy, comments_attributes: [:id, :bodycomment, :_destroy]])
在您也修复模型之前,这将不起作用...
accepts_nested_attributes_for :comments