Rails,删除属性 "undefined method '[]' for nil:NilClass" 时无法更新以使用 cocoon?

Rails, cant get update to work with cocoon when removing attribute "undefined method '[]' for nil:NilClass"?

我想知道是否有人可以告诉我为什么会出现此错误 "undefined method '[]' for nil:NilClass"。当我删除带有茧的图片并尝试更新时会发生这种情况。该方法适用于将图片添加到已编辑的画廊,但在删除和更新时出现此错误。我尝试使用 unless @pictures.blank? end 我假设问题出在 cocoon 删除图片时,但我不确定从那里该怎么做。服务器错误是,

Started PATCH "/galleries/41" for ::1 at 2017-05-07 16:03:02 +1000
Processing by GalleriesController#update as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"cG1UXCvODhYzqqAr++EAn8GvMVk7+t/eASkzDDOoPmJfw3l6ax/F2xXMhvs7FcrJ3LOuTd0sks5+2fb86kQv0Q==", "gallery"=>{"name"=>"Hellooo", "cover"=>"123456", "pictures_attributes"=>{"0"=>{"_destroy"=>"1", "id"=>"47"}, "1"=>{"_destroy"=>"1", "id"=>"48"}}}, "commit"=>"Update Gallery", "id"=>"41"}
  Gallery Load (0.0ms)  SELECT  "galleries".* FROM "galleries" WHERE "galleries"."id" = ? LIMIT ?  [["id", 41], ["LIMIT", 1]]
Unpermitted parameter: pictures_attributes
   (0.0ms)  begin transaction
  User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  (0.0ms)  commit transaction
Completed 500 Internal Server Error in 4ms (ActiveRecord: 0.0ms)

NoMethodError (undefined method `[]' for nil:NilClass):
...

也许如果有人能向我解释一下就太好了!

_form.html.erb

<%= form_for(@gallery, multipart: true) do |f| %>
  <div class="field">
    <%= f.label :name %>
    <%= f.text_field :name %>
  </div>
  <div class="field">
    <%= f.label :cover %>
    <%= f.text_field :cover %>
  </div>
  <div id="pictures">
    <%= f.fields_for :pictures do |pic| %>
    <%= render 'picture_fields', f: pic %>
  </div>
  <% end %>

    <div class="links">
      <%= link_to_add_association 'add picture', f, :pictures %>
  <%= f.submit %>
  </div>
<% end %>

_picture_fields.html.erb

<div class="nested-fields">
  <div class="field">
    <%= f.label :picture %>
    <%= f.file_field :picture, multiple: true, name: "pictures[picture][]" %>
    <%= link_to_remove_association "remove picture", f %>
  </div>
</div>

画廊控制器

def update
    @gallery = Gallery.find(params[:id])
    if @gallery.update(gallery_params)
       params[:pictures][:picture].each do |pic|
       @pictures = @gallery.pictures.create!(picture: pic)
      end
      flash[:success] = "Gallery Updated!"
      redirect_to root_url
    else
      render 'edit'
    end
  end

编辑:添加 gallery_params

def gallery_params
   params.require(:gallery).permit(:id, :name, :user_id, :cover, picture_attributes: [:id, :gallery_id, :picture, :_destroy])
  end

编辑:使用 cocoon 添加了创建操作和服务器日志

 def create
    @user = User.first
    @gallery = @user.galleries.build(gallery_params)
    if @gallery.save       
       flash[:success] = "Picture created!"
       redirect_to root_url
    else
     render 'new'
   end
 end

服务器日志

Started POST "/galleries" for ::1 at 2017-05-10 13:18:43 +1000
Processing by GalleriesController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"XU3z2jMdbselPJZ2SdZdGPwiAebiPznt8GWRqmbv8LM/MIxO+sNo1z2NTaDQ3nJNm0qaBJ66ny5254MPpHZaQQ==", "gallery"=>{"name"=>"Hello", "cover"=>"123456", "pictures_attributes"=>{"1494386318553"=>{"picture"=>#<ActionDispatch::Http::UploadedFile:0xac59228 @tempfile=#<Tempfile:C:/Users/Lee/AppData/Local/Temp/RackMultipart20170510-7596-16xlrir.jpg>, @original_filename="Skateboard 1.jpg", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"gallery[pictures_attributes][1494386318553][picture]\"; filename=\"Skateboard 1.jpg\"\r\nContent-Type: image/jpeg\r\n">, "_destroy"=>"false"}, "1494386321001"=>{"picture"=>#<ActionDispatch::Http::UploadedFile:0xac59150 @tempfile=#<Tempfile:C:/Users/Lee/AppData/Local/Temp/RackMultipart20170510-7596-jxo0st.jpg>, @original_filename="Skateboard 2.jpg", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"gallery[pictures_attributes][1494386321001][picture]\"; filename=\"Skateboard 2.jpg\"\r\nContent-Type: image/jpeg\r\n">, "_destroy"=>"false"}}}, "commit"=>"Create Gallery"}
  User Load (0.0ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
   (0.0ms)  begin transaction
  User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
   (0.0ms)  rollback transaction
  Rendering galleries/new.html.erb within layouts/application
  Rendered galleries/_picture_fields.html.erb (1.0ms)
  Rendered galleries/_picture_fields.html.erb (0.5ms)
  Rendered galleries/_picture_fields.html.erb (0.5ms)
  Rendered galleries/_form.html.erb (42.0ms)
  Rendered galleries/new.html.erb within layouts/application (58.5ms)
Completed 200 OK in 157ms (Views: 139.3ms | ActiveRecord: 0.0ms)

您的 gallery_params 方法似乎不允许您的 pictures_attributes。您没有 post 该代码,但我在错误日志 Unpermitted parameter: pictures_attributes 中注意到,这意味着您的强参数(gallery_params 方法)正在过滤掉这些参数。

基本上,强参数的全部意义在于确保您只传递您实际想要传递的键。所以你的控制器就像 "Nobody told me I am supposed to accecpt picture_attributes so I won't allow them through." 然后你的代码期望图片数组中有一个图片对象,但是图片数组没有导致错误的图片对象。

你能post画廊参数的代码吗?你也可以 post params 的内容吗?完全披露:我真的不知道 rails 5 所以可能还有其他一些事情在发生。

嗯。使困惑。没有 params[:pictures] 所以显然是 nil (检查您在顶部发布的日志)。所以这是导致错误的原因。如果您正在寻找张贴的图片,您应该参考 params[:pictures_attributes],但甚至不确定您要在那里做什么:为每个张贴的图片创建一个空图片(再次?)?图片通过gallery.update(gallery_params)保存。

注意:迭代发布的参数恕我直言绝对是错误的,因为如果删除一个,它仍然会在嵌套参数 _destroy 设置为 true 的情况下发布,因此可以从数据库中正确删除, 或者如果图片已经存在,它也将再次发布(并且不保存,因为它已经存在)。

[编辑] 添加简短的解决方案:

  • 在您的视图中使用 f.fields_for :pictures:这将遍历画廊现有的图片,并允许 delete/edit 现有图片,并向画廊添加新图片
  • 修复你的gallery_params并允许pictures_attributes(而不是单数形式)(否则什么都不会保存)
  • 在你的控制器中只写 @gallery.update_attributes(gallery_params) 并且根本不要迭代 params[:pictures] (删除那部分)它应该可以正常工作(因为 update_attributes 已经完成了这个,至少如果你想手动迭代使用 pictures_attributes)