accepts_nested_attributes_for rails 4未删除

时间:2013-11-21 10:10:43

标签: ruby-on-rails ruby ruby-on-rails-4

我现在已经阅读和研究了大约3天。 这是我的最后一招。

land.rb:

has_many :uploads , :dependent => :destroy
accepts_nested_attributes_for :uploads, :allow_destroy => true,:reject_if => :all_blank

upload.rb

belongs_to :land

_land_form_partial.html.erb

<%= form_for land , :html => {:multipart => true} do |f| %>

    <%= f.fields_for :uploads do |builder| %>
        <div class="land_fields">
            <%= builder.label :filename, "Image" %>
            <%= builder.text_field :filename %>   <br/>
            Delete: <%= builder.check_box :_destroy %>
        </div>
    <% end %>
 #... buttons and other fields
<% end %>

lands_controller.rb

def update
    if @land.update_attributes(land_params)
      flash[:success] = "Land updated"
      redirect_to lands_path
    else
      flash[:alert] = @land.errors.full_messages.first
      redirect_to edit_land_path
    end
  end

 def land_params  
    params.require(:land).permit( uploads_attributes: [ :id, :filename ]  )
  end

当我在文本字段中添加内容并更新它时,所有更新都正确。如果我单击复选框,它将不会删除该字段。

有人可以对此有所了解吗?

此外我尝试awesome_nested_fields除了删除实际记录外,一切正常。

提前谢谢。

编辑:解决方案:(我喜欢把解决方案放在问题中以防万一有人想在移动设备上查看它,因为我讨厌当我无法立即看到解决方案时)

感谢@nTraum

def land_params  
    params.require(:land).permit( uploads_attributes: [ :id, :filename, :_destroy ]  )
end

一切都会花花公子:)

2 个答案:

答案 0 :(得分:51)

您还需要允许嵌套模型的:_destroy参数,因为当您选中表单中的“删除”复选框时会使用此参数。这是Rails标记必须销毁的模型实例的方式。

def land_params  
  params.require(:land).permit(uploads_attributes: [:id, :filename, :_destroy])
end

答案 1 :(得分:12)

OP没有和我一样的问题,但对于遇到这个问题的任何人来说,对我来说,allow_destroy: true调用accepts_nested_attributes时没有/* Head Master Info >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */ /* Top Level Google Drive Folder ID */ var TopDriveFolderID = "0B2rN5b8fW77ldXZXOXFLZGlSamc"; var BaseNumberOfFilesInFolder = 4; var NewSSAnalyzerSheetId = "1VyL8XL1x41H6yetcrwfUhVcch-DUsngY4-bHCbo-_xM"; /* End Head Master Info >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ /* Body >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ /* Functions to iterate through all sub folders */ function listFolders() { var parentFolder = DriveApp.getFolderById(TopDriveFolderID); var childFolders = parentFolder.getFolders(); while(childFolders.hasNext()) { var child = childFolders.next(); // Logger.log(child.getName() + " |Drive_ID: " + child.getId()); var folderId = child.getId(); // **the folderId Variable is also the folder ID, // hence they are used interchangeably ** /* SpreadSheet Combiner >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ /* Name of combined Spreadsheet*/ var newSpreadSheetName = DriveApp.getFolderById(folderId).getName(); /* Retrieve the desired folder */ var myFolder = DriveApp.getFolderById(folderId); /* Get all spreadsheets that resided on that folder */ var spreadSheets = myFolder.getFilesByType("application/vnd.google-apps.spreadsheet"); var spreadSheetName = myFolder.getName(); // Logger.log(spreadSheetName); /* Check if a file needs to be created or if one already exists*/ var theFolder = DriveApp.getFolderById(folderId); var files = theFolder.getFiles(); var fname = theFolder.getName(); var cnt = 0; var file; /* Check the quantity of files in a folder to see if you need to combine the sheets and create a file*/ while (files.hasNext()) { cnt++; file = files.next(); //Logger.log(file.getName()); if (cnt > BaseNumberOfFilesInFolder) { Logger.log("File already exists") break; } ; }; // If a file needs to be created this checks it and creates it Logger.log(cnt + " is the number of files '"+ newSpreadSheetName+ "' has."); if (cnt > BaseNumberOfFilesInFolder){ Logger.log("No file needs to be created") }else{ /* Create the new spreadsheet that you store other sheets */ var newSpreadSheet = SpreadsheetApp.create(newSpreadSheetName); /* Iterate over the spreadsheets over the folder */ while(spreadSheets.hasNext()) { var sheet = spreadSheets.next(); /* Open the spreadsheet */ var spreadSheet = SpreadsheetApp.openById(sheet.getId()); /* Get all its sheets */ for(var y in spreadSheet.getSheets()) { /* Copy the sheet to the new merged Spread Sheet */ spreadSheet.getSheets()[y].copyTo(newSpreadSheet); /* In order to move the file to the folder we want and because google considers the SpreadSheet a Google Spreadsheet instead of a file, we have to convert the SpreadSheet to a file in order to move it.Thats what the next 2 lines of code do.*/ var getNewSSid = newSpreadSheet.getId(); var SStoGFile = DriveApp.getFileById(getNewSSid); /* Actually moving the file*/ DriveApp.getFolderById(folderId).addFile(SStoGFile); /* Deleting the duplicate file that was created in the process*/ var rootFolder = DriveApp.getRootFolder(); DriveApp.getRootFolder().removeFile(SStoGFile); } } /*Code to add our base analysis template to the new combined template that was created;*/ //Grabs the template var sss = SpreadsheetApp.openById(NewSSAnalyzerSheetId); //replace with source ID var ss = sss.getSheetByName('Analysis Tab'); //replace with source Sheet tab name var range = ss.getRange('A1:E6'); //assign the range you want to copy var data = range.getValues(); //Copies the template info into the current newly created sheet var tssId = newSpreadSheet.getId(); var tss = SpreadsheetApp.openById(tssId); //replace with destination ID var ts = tss.getSheetByName('Sheet1'); //replace with destination Sheet tab name ts.getRange(1,1,6,5).setValues(data); //you will need to define the size of the copied data see getRange() Logger.log("New File was created with the name - " + newSpreadSheetName) } }; /* End SpreadSheet Combiner >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ getSubFolders(child); } /* Necessary Function to help the above loop through the sub folders */ function getSubFolders(parent) { parent = parent.getId(); var childFolder = DriveApp.getFolderById(parent).getFolders(); while(childFolder.hasNext()) { var child = childFolder.next(); Logger.log(child.getName()); getSubFolders(child); } return; } /* End iterate through Sub Folders */。模特。