庖丁解views

我们使用

  1. rails g scaffold user name:string password:string
  2. tree blog/app/views
  3. blog/app/views
  4. ├── layouts
  5. └── application.html.erb
  6. └── users
  7. ├── _form.html.erb
  8. ├── edit.html.erb
  9. ├── index.html.erb
  10. ├── index.json.jbuilder
  11. ├── new.html.erb
  12. ├── show.html.erb
  13. └── show.json.jbuilder
  14. 2 directories, 8 files

去掉jbuilder,api文件,和视图无关

  1. tree blog/app/views
  2. blog/app/views
  3. ├── layouts
  4. └── application.html.erb
  5. └── users
  6. ├── _form.html.erb
  7. ├── edit.html.erb
  8. ├── index.html.erb
  9. ├── new.html.erb
  10. ├── show.html.erb
  11. 2 directories, 8 files

总结一下里面的特点

  • index是显示列表
  • new和edit都复用_form
  • show显示出所有即可

我们想一下jade是否也可以呢?

jade特性

  • block和extend是布局
  • include是包含,可以实现引用_form类似的
  • foreach类的也支持

所以jade实现erb的功能毫无问题

实现列表

index.html.erb

  1. <h1>Listing users</h1>
  2. <table>
  3. <thead>
  4. <tr>
  5. <th>Name</th>
  6. <th>Password</th>
  7. <th colspan="3"></th>
  8. </tr>
  9. </thead>
  10. <tbody>
  11. <% @users.each do |user| %>
  12. <tr>
  13. <td><%= user.name %></td>
  14. <td><%= user.password %></td>
  15. <td><%= link_to 'Show', user %></td>
  16. <td><%= link_to 'Edit', edit_user_path(user) %></td>
  17. <td><%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %></td>
  18. </tr>
  19. <% end %>
  20. </tbody>
  21. </table>
  22. <br>
  23. <%= link_to 'New User', new_user_path %>

转成jade就无比简单了

  1. extends ../layouts/layout
  2. block content
  3. h1 Listing orders
  4. table
  5. thead
  6. tr
  7. each n in ['name','password']
  8. th #{n}
  9. th(colspan="3")
  10. tbody
  11. each order in orders
  12. tr
  13. each n in ['order.name','order.password']
  14. td #{ eval(n) }
  15. td
  16. a(href='/orders/#{ order._id}') Show
  17. td
  18. a(href='/orders/#{ order._id}/edit') Edit
  19. td
  20. a(onclick="click_del('/orders/#{ order._id}/')") Delete
  21. br
  22. p
  23. a(href='/orders/new') New Order
  • erb里使用 @users
  • 而jade里使用[‘name’,’password’]

效果是一样的。

实现创建和编辑

那么创建呢?

new.jade

  1. extends ../layouts/layout
  2. block content
  3. h1 New order
  4. include order
  5. a(href='/orders') Back

其核心在include order的order.jade里

这里的order用_form也不是不可以,不过没啥大劲

jade里还有一个特性,include文件,可以把上下文里的文件同名对象也传进去。也就是我include 的order,如果上下文里有的order,的order.jade里。

即减少代码转换,又精简代码,何乐而不为呢?

创建和更新都是类似,我们先看一下更新的edit.jade

  1. extends ../layouts/layout
  2. block content
  3. h1 Editing order
  4. include order
  5. a(href='/orders/#{ order._id}') Show
  6. span |
  7. a(href='/orders') Back

和创建基本无大差别,文字和url稍有变化而已。

看一下order.jade

  1. - var _action = order._action == 'edit' ? '#' : '/orders/'
  2. - var _method = order._action == 'edit' ? "" : "post"
  3. - var _type = order._action == 'edit' ? "button" : "submit"
  4. - var onClick = order._action == 'edit' ? "click_edit('order-" + order._action + "-form','/orders/" + order._id + "/')" : ""
  5. form(id='order-#{ order._action}-form',action="#{_action}", method="#{_method}",role='form')
  6. each n in ['order.name','order.password']
  7. - m = eval(n);
  8. div(class="field")
  9. label #{n.split('.')[1]} #{m}
  10. br
  11. input(type='text',name="#{n.split('.')[1]}" ,value="#{ m == undefined ? '' : m }")
  12. div(class="actions")
  13. input(type='#{_type}',value='Submit',onClick='#{onClick}')

这个代码有点丑陋,为了兼容创建和更新,所以定义了几个变量的。

说明

  • form表单处理请求,form的action约定了
  • 提交分2种
    • 创建,就直接post提交
    • 更新交给了onClick变量对应的click_edit方法(位于public/javascripts/app.js)

看一下这个前端js吧

  1. function click_edit(id, url){
  2. // $('#' + id).attr('action','#');
  3. console.log(url);
  4. if (!confirm("确认要更新?")) {
  5. return window.event.returnValue = false;
  6. }
  7. var form = document.querySelector('form')
  8. var data = form2obj(form);
  9. console.log(data);
  10. // return false;
  11. $.ajax({
  12. type: "PATCH",
  13. url: url,
  14. data : data
  15. })
  16. .done(function( res ) {
  17. if(res.status.code == 0){
  18. // alert( "Data delete: success " + res.status.msg );
  19. window.location.href= res.data.redirect;
  20. }else{
  21. alert( "Data delete fail: " + res.status.msg );
  22. }
  23. });
  24. return false;
  25. }

简单的更新,使用PATCH方法而已。这里有一个知识点

  1. var data = form2obj(form);

把表单里的内容转换成ajax里的传值对象,算是个tips吧(具体见public/javascrips/form2obj.js)。

实现删除

首先index.jade里有删除功能

  1. td
  2. a(onclick="click_del('/orders/#{ order._id}/')") Delete

根据rest路由,我们一般的做法

  1. DELETE /users/:id(.:format) users#destroy

也就是我delete请求到/users/:id即可

即,对应的是click_del方法(位于public/javascripts/app.js)

  1. function click_del(url){
  2. if (!confirm("确认要删除?")) {
  3. return window.event.returnValue = false;
  4. }
  5. console.log(url);
  6. $.ajax({
  7. type: "DELETE",
  8. url: url
  9. })
  10. .done(function( res ) {
  11. if(res.status.code == 0){
  12. // alert( "Data delete: success " + res.status.msg );
  13. window.location.href= location.href;
  14. }else{
  15. alert( "Data delete fail: " + res.status.msg );
  16. }
  17. });
  18. }

jade版的crud

详情如下

  1. mvc git:(master) tree app/views/orders
  2. app/views/orders
  3. ├── edit.jade
  4. ├── index.jade
  5. ├── new.jade
  6. ├── order.jade
  7. └── show.jade
  8. 0 directories, 5 files

jade版的依赖js

  • app.js
    • click_del删除方法
    • click_edit编辑方法
  • form2obj.js
  1. mvc git:(master) tree public
  2. public
  3. ├── 404.html
  4. ├── 422.html
  5. ├── 500.html
  6. ├── favicon.ico
  7. ├── images
  8. ├── javascripts
  9. ├── app.js
  10. └── form2obj.js
  11. ├── robots.txt
  12. ├── stylesheets
  13. └── style.css
  14. └── uploads
  15. 4 directories, 8 files

layout

最后再简单的介绍一下layout.jade

上面已知依赖

  • app.js
    • click_del删除方法
    • click_edit编辑方法
  • form2obj.js

如果我让生成的代码看不到app和form2obj的存在,生成的代码就可以复用了,是不是?

其实丢在布局文件里就可以

  1. doctype html
  2. html
  3. head
  4. title= title
  5. link(rel='stylesheet', href='/stylesheets/style.css')
  6. link(href="http://libs.baidu.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet")
  7. body
  8. block content
  9. script(src="http://libs.baidu.com/jquery/1.9.0/jquery.js")
  10. script(src="http://libs.baidu.com/bootstrap/3.0.3/js/bootstrap.min.js")
  11. script(src='/javascripts/form2obj.js')
  12. script(src='/javascripts/app.js')

说明

  • 引了jq和bootstrap
  • 引了app.js
  • 引了form2obj.js

简单吧?