165 : 批量修改记录(Edit Multiple)
查看原版Railscast
译者:darkbaby123
校对:本文现在暂无校对者,如果哪位兄弟热心帮忙,可以联系蜗牛同学,或者给我发消息
第52集
演示了如何编辑多条数据库记录的例子。那个示例程序允许你一次选中多个任务,然后每个被选中的任务(Task
)都会被设置成“完成”。
这一集中我们将对这种想法进行扩展。但这次,我们可以让用户选择更新一批记录的多个属性,而不是上一集的单个属性。
网上商店应用程序
下面显示的就是我们要改造的应用程序。目前,如果我们要修改表格的最后两条记录,就要单独编辑它们。如果要修改的记录很少,这不成问题。但如果面对成堆的记录这就很乏味了。下面我们将修改这个程序,让它可以同时修改一批记录的多个属性。
修改index视图
我们将在每条产品之前加上一个checkbox,这样我们可以轻易地选择要修改的产品。但在此之前,我们先把显示所有产品的table标签用form包起来。目前我们在Controller层还没有一个用来编辑多个产品的action,所以先把url地址空着,以后再来填吧。
<% form_tag ... do %>
我们没有为form指定提交方式,所以它默认是POST。虽然这个form将带我们到一个显示所有选中产品的新页面,我们似乎应该用GET,但因为我们要传递多个产品的id过去,这是GET做不到的。
在table的每一行中,我们要加入一个checkbox,它的值是对应的产品的 id
(还要在table的标题部分加上一个空的<th>
,保证表格是对齐的)。
<td><%= check_box_tag "product_ids[]", product.id %></td>
注意check_box_tag的name,它是以一个方括号结尾的,这是所有传上去的值将会被集合成一个数组。
最后我们在table下面加上提交按钮。
<%= submit_tag "Edit Checked" %>
现在我们的index视图应该是这个样子:
<h1>Products</h1>
<% form_tag ... do %>
<table>
<thead>
<tr>
<th>Name</th>
<th>Category</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<% for product in @products %>
<tr>
<td><%= check_box_tag "product_ids[]", product.id %></td>
<td><%= product.name %></td>
<td><%= product.category.name %></td>
<td><%= number_to_currency product.price, :unit => "£" %></td>
<td><%= link_to "Edit", edit_product_path(product) %></td>
<td><%= link_to "Destroy", product_path(product), :confirm => "Are you sure?", :method => :delete %></td>
</tr>
<% end %>
</tbody>
</table>
<%= submit_tag "Edit Checked" %>
<% end %>
<%= link_to "New Product", new_product_path %>
修改products控制器
我们的products控制器包含了有用的RESTful action。现在我们要增加两个action来编辑和更新多条记录。
def edit_multiple
end
def update_multiple
end
这两个action的用处和标准的 edit
和 update
差不多,但它们用来处理多条记录的编辑和更新。其中 edit_multiple
方法需要对应的视图,我们过一会儿再写它。
在我们的程序中,Products
是一个RESTful资源,所以我们必须修改routes文件使这两个新action可以访问。因为我们要对products集合添加方法,所以我们用 :collection
参数添加这两个方法。
map.resources :products, :collection => { :edit_multiple => :post, :update_multiple => :put }
:collection
参数需要一个hash,其中hash的键代表action的名字,值代表这个action的html method。如同上文提到的,我们采用POST作为 edit_multiple
的method,虽然理想情况下我们应该用GET。
现在我们的action定义好了,我们可以回到index视图,给 form_tag
填上正确的url地址
<% form_tag edit_multiple_products_path do %>
现在我们刷新index页面,就可以看到每个产品前面的checkbox,下面的“Edit Checked”按钮会带我们到edit_multiple页面。
新的form
如果我们选中一些产品,然后点击下面的"Edit Checked"按钮,会看到一个missing template错误。这是因为我们还没有创建视图代码,所以下一步工作就是完成它。我们将把视图代码写在 /app/views/products/edit_multiple.html.erb
文件中。但在此之前,我们先看看点击按钮后,development日志中生成的信息。
Processing ProductsController#edit_multiple (for 127.0.0.1 at 2009-06-06 19:24:37) [POST]
Parameters: {"product_ids"=>["3", "4", "5"], "commit"=>"Edit Checked", "authenticity_token"=>"s5z3KEJpBM7zC2JooC/relZ2oZtVpfxL/IMklpcBuYU="}
在Parameters部分,我们可以看到我们选中的产品的id以数组的形式组织着。在控制器中,我们将用这些参数找到之前选中的产品。
def edit_multiple
@products = Product.find(params[:product_ids])
end
现在转到我们的edit_multiple视图。在我们之前的程序中,我们已经有了一个放在partial中的form,它用在新建和编辑产品的页面。看起来似乎我们可以直接把这个form拿过来用。但因为它做一些修改来适应批量记录,所以我们干脆建立一个新的form。
在视图的开头我们先定义一个没有关闭block的 form_for
(译者注:原文写的form_tag,但实际代码是form_for,所以翻译时改了一下)。因为这个form是用来更新多个产品的,我们为它的第一个参数指定一个symbol而不是实际的Product对象。我们还要为它指定 :url
和 :method
(注意是PUT,所以要单独指定)。
<% form_for :product, :url => update_multiple_products_path, :html => { :method => :put } do |form| %>
在form中我们需要设定所有选中的产品的 id
s,否则form提交时,我们不知道哪些产品会被更新。我们可以用一系列的hidden_field_tag来存放产品的 id
s,同时我们做一个列表来显示这些待更新的产品。
<ul>
<% for product in @products %>
<li>
<%= h product.name %>
<%= hidden_field_tag "product_ids[]", product.id%>
</li>
<% end %>
</ul>
下一步,我们将为form添加表单元素来表示 Product
的属性。这些属性包括产品名称、分类名称、价格、和是否停售的信息。当我们提交这个form时,我们只希望更新那些填写了具体值的属性。所以对那些有一系列选择的下拉框,我们要加一个空选项,这样用户就可以选择“空”来跳过这些属性的修改。
<ol class="formList">
<li>
<%= form.label :category_id %>
<%= form.collection_select :category_id, Category.all, :id, :name, :include_blank => true %>
</li>
<li>
<%= form.label :name %>
<%= form.text_field :name %>
</li>
<li>
<%= form.label :price %>
<%= form.text_field :price %>
</li>
<li>
<%= form.label :discontinued %>
<%= form.select :discontinued, [["Yes", true], ["No", false]], :include_blank => true %>
</li>
<li>
<%= form.submit "Submit" %>
</li>
</ol>
最后,我们关闭 form_for
的block,我们的form也完成了。
<% end %>
现在如果我们刷新页面,我们会看到我们选中的产品的列表,还有下面用来修改产品信息的form。注意所有的下拉框都已经被设置成了空值,这样我们就不会去修改它们的在数据库中的值。
编写用于更新的action
现在我们已经几近完成了,但我们还要为 update_multiple
方法编写代码,当上图的form提交时,更新所有被选中的产品。
def update_multiple
@products = Product.find(params[:product_ids])
@products.each do |product|
product.update_attributes!(params[:product].reject { |k,v| v.blank? })
end
flash[:notice] = "Updated products!"
redirect_to products_path
end
在 update_multiple
的开始,我们用产品的 id
s 数组(从form的隐藏字段中传上来的)获取了被选中的产品,然后我们遍历每个产品并进行更新。因为我们只要更新不为空的属性,所以我们用 reject
遍历每一个参数,去掉了值为空的属性。注意我们用的是带感叹号(!)的 update_attributes!
方法,因为我们没有对模型做任何校验。如果这个程序是一个实际产品,我们会去做校验,但这超出了这一集讨论的范围。使用 update_attributes!
表示如果有些数据不正确,程序将会抛出异常。一旦所有的产品都更新完成,我们设置一个flash信息然后跳转回到产品列表页面。
让我们看看它是否能正常工作。我们有两个产品,Video Game Console和Video Game Disc,被放在Toys & Games分类下。现在我们要把分类改成Electronics。如果我们选中这两个产品并点击“Edit Checked”按钮(译者注:原文是“Submit”按钮,但实际页面上是"Edit Checked")。我们将会看到它们被列在edit_multiple页面上。
如果我们选择从category下拉框中选择“Electronics”然后点击“Submit”按钮,我们会回到产品列表页面。
可以看到,这两个产品的分类已经改成了“Electronics”,但其他的属性都没有变化。
更进一步
目前我们已经提供了一种很有效的方式去同时修改多个模型对象。但在这一集的结尾,我们将更进一步,让价格可以按相对的数值来改变。比如,这样我们就可以让所有家具的价格降低20%。我们现在可以选中多个产品,但如果我们改变form中的价格,那么所有的产品都会变成一样的价格。如果我们利用虚拟属性,更改相对价格的逻辑就变得非常直观。虚拟属性在第16集中有介绍,如果想了解它们,你可以去 看看视频
或 读读文章
。
我们将在 Product
模型中创建一个虚拟属性price_modification
。我们会修改 edit_multiple
视图中的form这样它会修改我们的新属性而不是直接修改 price
属性。
<li>
<%= form.label :price_modification %>
<%= form.text_field :price_modification %>
</li>
现在我们要在 Product
模型中设定新属性的getter和setter。
class Product < ActiveRecord::Base
belongs_to :category
def price_modification
price
end
def price_modification=(new_price)
if new_price.ends_with? "%"
self.price += (price * (new_price.to_f / 100)).round(2)
else
self.price = new_price
end
end
end
getter方法很直观:我们只需要返回price就行,但setter方法稍微复杂一点。如果输入的值(new_value)以百分号结束,我们将把值转换成浮点数(new_price.to_f
),除以100然后乘以原始的价格,来求出价格改变的具体数值。然后把它和原始价格相加。如果那个具体数值是负数,价格就会降低。最后,我们用ActiveSupport扩展的 round
方法让新的价格保留小数点后两位。
现在,让我们开始贱卖家具。我们选中两个家具产品然后修改他们。
然后在“Price modification”一栏中,填写“-20%”。
当我们提交form并返回产品列表,我们可以看到选中的那些产品都降价了20%。
这一集中讲的技术非常有用,并且可以应用在一系列的场景中。经过这次实验,你应该可以发现在你的Rails应用的很多地方,能相对地修改属性都是非常有用的。
分享到:
相关推荐
修改字体: 默认Studio3t的字体太小,需要修改字体: 点击菜单:Edit--->Preferences 右键创建的database,选择Add Collection创建新的Collection
太强悍:500k胜过cool edit pro 30M等声音编辑软件,渐入,渐出等功能强大 这么好的免费软件!真的需要很有缘份,才能收藏到! 就是因为有这些牛人!国外的软件才这么牛吧!
File Property Edit 3.02(批量修改文件或目录的属性和摘要属性)
批量修改是指一次性对多个数据记录进行更新,而不是逐个修改。在DataGridView中,可以通过编程实现选中行的批量更新。首先,我们需要获取选中行的索引,然后遍历这些行,提取每行的数据,最后通过数据库连接执行...
通过菜单栏选择"Edit" -> "Export to Spread",然后按照向导步骤操作,最终在生成的Excel表格中修改"Footprint"列的值,如图10所示。修改完成后,更新文件,原理图中的元件封装就会发生变化。 2. PCB图中批量修改...
标题中的“DICOM文件批量修改添加工具”是一款专门针对DICOM文件设计的应用程序,能够帮助用户快速、高效地对大量DICOM文件进行信息修改或添加操作。这对于医院信息系统集成、影像数据库管理、研究项目或数据分析等...
在标题“修改WINDOW源码中的EDIT,实现透明EDIT”中,我们探讨的是如何对Windows内核的EDIT控件进行源代码级别的修改,以达到透明效果。这是一项高级的Windows API编程技术,涉及到对操作系统底层的理解和直接操作。...
这个汉化版本是针对原版D3Edit的中文翻译版,使得中国玩家能够更方便地理解和使用该工具,无需担心语言障碍。 首先,我们需要理解D3Edit的基本功能。它主要涵盖了以下几个方面: 1. **角色属性修改**:玩家可以...
《AndroidResEdit:安卓应用汉化与签名修改利器》 在安卓应用开发和本地化过程中,AndroidResEdit是一款不可或缺的工具。它专为Android APK文件设计,提供了强大的资源编辑功能,使得非编程背景的用户也能方便地...
通常,Edit控件用于用户输入文本,但在我们的场景下,我们将用它来显示和记录操作日志。 要实现这个功能,我们首先要创建一个CEdit对象,并将其添加到对话框或视图中。在对话框资源编辑器中,选择一个Edit控件,...
批量编辑json文件 该工具旨在: 简单的 方便的 快速(并行执行IO操作) 安装 npm install -g batch-edit-json 使用 Usage: batch-edit-json [-vd] [--remove =< key> ]... [--add =< object > ]... [--...
在本文中,我们将介绍两种批量修改的方法:通过全局修改(Global edit)和使用Footprint Manager。 方法一:使用Footprint Manager 在Altium Designer中,可以通过Tools下的Footprint Manager来批量修改名称、数值...
简单获取Windows时间-Delphi源代码,改时间的小程序,在Windows自带的时间管理中也可完成系统时间的修改,这个只是一个帮助了解Windows与Delphi编程的例子,如何通过Delphi的程序来修改Windows时间,大致就是这样...
在硬件设计领域,特别是在进行大规模集成电路设计时,经常会遇到需要批量更改网络名称的情况。这通常发生在需要对CPLD(复杂可编程逻辑器件)进行网络重新分配的情况下。如果采用手动方式逐个修改网络名,不仅耗时耗...
根据文件信息,以下是对"OrCAD原理图中如何批量修改元件封装属性(FootPrint)"的知识点的详细介绍: OrCAD是由Cadence公司开发的一套集成电路设计软件,广泛用于电子设计自动化(EDA)。OrCAD套件包括OrCAD Capture...
2. **编辑功能**:TAP3Edit允许用户对TAP3文件进行编辑,如修改通话属性、添加或删除通话记录,这对于故障定位和数据修复至关重要。 3. **数据导出与导入**:支持将TAP3数据导出为多种格式,如CSV、Excel,方便...
* Edit-Shape edit:修改形状 * Edit-Z-Copy shape:复制 Z 轴图形 * Edit-Delete Unconnected Shapes:删除未连接的图形 * Edit-Split Plane-Parameters:分割平面参数 * Edit-Split Plane-Create:创建分割平面 * ...
procedure TForm1.Edit2Exit(Sender: TObject); begin if CheckBox1.Checked=true then edit2.text:=LowerCase(edit2.text) else edit2.text:=Uppercase(edit2.text) end; procedure TForm1.Edit3Exit...
4. **批量文件处理**:Edit Plus允许用户进行批量文件操作,如批量查找替换、批量重命名等,大大提升了文件管理的便捷性。 5. **内置FTP客户端**:软件内建FTP功能,可以直接连接到远程服务器进行文件上传和下载,...
Delphi写的中英文翻译程序源代码,好像调用的网址失效了,现在无法翻译了,这个程序和网络有关,同时实现对字符的控制,面向初学者。下面是核心的代码: procedure TForm1.BitBtn4Click(Sender: TObject); var ...