• 嵌套表单1-1
  • 嵌套表单1-多
  • 选日期时间的UI (一个jquery Plugin)
  • 拆除前后台css和js
  • Rich Editor, 显示输入的HTML tag
  • 批次编辑/删除

嵌套表单1-1

核心知识点:ActiveRecord Nested Attributes

嵌套属性的功能可以让你在关联的记录上保存属性,通过父记录。默认这个功能是关闭的。

使用类方法 #accepts_nested_attributes_for( :小写类名 ), 开启这个功能后,会增加一个属性存入方法,

如  profiles_attributes=(attributes)

⚠️::autosave被添加到关联上,当user更新, profile也自动更新。

实例方法:

:allow_destroy, 如果是true,任何删除record的行为,attributes_hash中会带一个_destroy key和a value("1"或true),对应的id的记录会被删除。

情景:

给User一个Profile,用于储存用户个人资料,1对1的关系。

model这样设计的原因是为了节省数据库的查询量。

单独的resource编辑UI

  1. 编辑一个嵌套的路由

    •    resources :users do
      resource :profile, :controller => "user_profiles"
      end
  2. 单独的连接,单独的edit表单, 单独的controller

使用accepts_nested_attributes_for方法编辑嵌套表单

  1. 在User.rb上加上accepts_nested_attributes_for :profile
  2. 在users_controller.rb上,把profile_attributes加入参数白名单。
    • :profile_attributes => [:id, ...]
  3. 在users_controller.rb上,edit方法上如果@user的profile不存在则创建一个(用关联方法)
    • @profile = @user.profile || @user.create_profile
  4. 在views/users/edit.html.erb上,塞入更新profile的表格。
    • f.field_for :profile do |ff|

方法:field_for(record_name, record_object=nil, field_options = {} , &block)

创建一个类似form_for的和指定model对象相关的scope,但不会创建form标签。

用于在一个form表格内添加额外的model对象。

和form_for类似,会生成FormBuilder对象(关联着model对象)

但参数有2个record_name和record_object用于不同的功能:

  1. record_name:  用于fields。提交的values出现在params hash中的样子。最终提交给controller。
  2. record_object(可选):what default values are shown when the form the fields appear in is first displayed。(没弄明白,但不重要,忽略)

嵌套表单(1-to-many)

def new
  @event = Event.new
  @event.tickets.build

end

在new方法中,每多加一行@event.tickets.build。在生成的表格中就多一个ticket输入框。

admin/events/_form.html.erb

<%= f.fields_for :tickets do |ff| %>
  <div class="form-group">
    <%= ff.label :name %>
    <%= ff.text_field :name, :class => "form-control"%>
  </div>
<% end %>

def edit
  if @event.tickets.empty?
    @event.tickets.build
  end
end

如果没有tickes则编辑时,增加一个ticket的输入框。

如果想要在编辑页面,新增功能:

  1. 增加一个“新增票”的按钮。点击后新增ticket输入框,新增一个ticket
  2. 在每个ticket输入框下面,增加一个“删除这个票据”的按钮。点击后删除这个ticket

需要使用javascript来实现相关功能。使用jQuery插件nested_form_fields gem

单独的rescources UI编辑

如果 has_many 的资料非常多、字段又多的话,就不适合用嵌套(Nested)表单 UI。


选日期时间的 UI

<%= f.date_select :birthday, :class => "form-control" %>

这是Rails内建的,有点丑,但所有浏览器都能用。

有:start_year, :end_year,等N多个选项



拆除前后台css和js

默认的 layout 是 app/views/layouts/application.html.erb

而后台的 controller 透过 layout "admin" 可以改用 :

app/views/layouts/admin.html.erb

但是有个部分我们没有拆开,那就是 css 和 javascript, 到目前还是共享:

app/assets/stylesheets/application.scss 和 app/assets/javascript/application.js

随着 Plugins 功能越装越多,有很多 css/js 前后台是不一样的,前台目前没有用到,但是因为前后台共享的关系,还是被用户下载了。

这部分的 css/js 也可以前后台拆开,除了可以让前台下载更有效率,也可以让代码分开管理。

方法:

1.

新增 app/assets/stylesheets/admin.scss

新增 app/assets/javascripts/admin.js

2. 修改 config/initializers/assets.rb

config/initializers/assets.rb

- # Rails.application.config.assets.precompile += %w( search.js )

+ Rails.application.config.assets.precompile += %w( admin.css admin.js )

3. 重启服务器后,更改admin.html.erb文件的<head> 为:

 <%= stylesheet_link_tag    'admin', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'admin', 'data-turbolinks-track': 'reload' %>

4. 挪动插件即可。



Rich Editor, 显示输入的HTML tag

simple_format方法的作用是换行,包裹一个<p>

去掉simple_format,  HTML 会完全被脱逸(escaped)了,例如 < 会变成 &lt;。这是 Rails 默认的安全机制。

如果使用 raw 或者 html_safe的话,如果是管理员后台操作倒没有问题,但前台用户使用的话容易被xss跨脚本攻击。

最好使用

sanitize 方法,白名单过滤sanitize(html, options = {})

可以设置白名单,单一定要全面:

tags: ["table", "tr", "td"]

attributes: ["border"]

或者在config/application.rb中设置

config.action_view.sanitized_allowed_tags = Rails::Html::WhiteListSanitizer.allowed_tags + %w(table tr td)
config.action_view.sanitized_allowed_attributes = Rails::Html::WhiteListSanitizer.allowed_attributes + %w(style border)

Rich Edit  ckeditor

编辑器:https://github.com/galetahub/ckeditor (Rails 5.1x, integration)

不是很流行的编辑器。

安装:

gem 'ckeditor', github: 'galetahub/ckeditor'

初始化:config/initializers/assets.rb

Rails.application.config.assets.precompile += %w( ckeditor/*)

使用:

从gem上加载editor: app/assets/javascripts/application.js:

//= require ckeditor/init

⚠️在//= require_tree.前面。

FormHelpers:

= form_for @page do |form|
= form.cktext_area :notes, ckeditor: { language: 'uk'}
= form.cktext_area :content, value: 'Default value', id: 'sometext'
= cktext_area :page, :info, cols: 40, ckeditor: { uiColor: '#AADC6E', toolbar: 'mini' }

toolbar可以客制化。具体其他的设置见git。



批量删除

  1. 设置routes。使用collection { post :bulk_update}
    • 如果routes使用delete。则对应的form_tag必须明确指定method: :delete。
    • 如果要用同一个
  2. 在index.html.erb上, 给table增加form_tag(),  check_box_tag(),和subimt_tag()。
  3. 增加<script> javascript。
  4. 修改controller, 增加bulk_update方法,使用Array[params[:ids]]循环遍历event,并删除。

重点:

第2步:请求参数的设置

<th><%= check_box_tag("全选", "1", false, id:"toggle_all" )%></th>

<td><%= check_box_tag("ids[]", event.id, false)%></td>

⚠️:

必须使用"ids[]",这样可以得到属性name="ids[]"

提交的时候,生成参数: "全选"=>"1", "ids"=>["22", "24",...] ,参数是由name/value对儿组成的。

因为如果name是'ids' ,这是一个string,提交生成的参数只会取完全相同的名字的第一个value,生成 "ids"=>"26",  造成批量删除功能失败。

第三步:用到增加和移除属性的method: setAttribute(), removeAttribute(),

也使用了querySelectorAll()获得一个数组的checkbox tag,然后循环forEach()

document.getElementById("toggle_all").addEventListener("click", function(){
 if (this.hasAttribute("checked") == false ) {
  this.setAttribute("checked", "checked");
    document.querySelectorAll("input[name='ids[]']").forEach(function(e){
    e.setAttribute("checked", "checked");
  })
 } else {
  this.removeAttribute("checked");
    document.querySelectorAll("input[name='ids[]']").forEach(function(e){
   e.removeAttribute("checked");
 })

})})


批次修改:

一个form的url是固定的,也只能绑定一个action, ,同时form不能嵌套,如果想要多个批量功能,怎么办?

上节使用form_tag(bulk_update_admin_events_path),因此地址指向确定。HTML方法是post。

办法:

提交按钮<input type="submit" name="commit", value="XXX">的name/value属性对儿,在request params中会出现,如"commit"=>"批次删除"。

因此不同按钮使用不同的name,即可区别不同的功能要求,然后在controller的action中使用if进行判断。

def bulk_update
 total = 0
 if params[:commit] == I18n.t(:bulk_update) && params[:ids]
  Array(params[:ids]).each do |event_id|
   event = Event.find(event_id)
   event.status = params[:status]
   event.save
   total += 1
  end
  flash[:notice] = "批量变更状态为#{params[:status]}"
 elsif params[:commit] == I18n.t(:bulk_delete) && params[:ids]
  Array(params[:ids]).each do |event_id|
   event = Event.find(event_id)
   event.destroy
   total += 1
  end
  flash[:alert] = "成功删除#{total}笔"
 end

redirect_to admin_events_path
end

⚠️: I18n.t(:bulk_delete)加上的话,需要在en.yml和zn-CH.yml上加上对应的翻译。

Rails-Treasure chest2 嵌套表单;的更多相关文章

  1. Rails-Treasure chest3 嵌套表单; Ransack(3900✨)用于模糊查询, ranked-model(800🌟)自订列表顺序; PaperTrail(5000✨)跟踪model's data,auditing and versioning.

    自订列表顺序, gem 'ranked-model' 多步骤表单 显示资料验证错误讯息 资料筛选和搜寻, gem 'ransack' (3900✨); 软删除和版本控制 数据汇出(csv), 自订列表 ...

  2. Rails中关联数据表的添加操作(嵌套表单)

    很早就听说有Web敏捷开发这回事,最近终于闲了下来,可以利用业余的时间学些新东西,入眼的第一个东东自然是Ruby on Rails.Rails中的核心要素也就是MVC.ORM这些了,因此关于Rails ...

  3. selenium——表单嵌套

    <html> <iframe id="id-iframe" name="iframee1"> --切换表单 <html> & ...

  4. Angular 表单嵌套、动态表单

    说明: 组件使用了ng-zorro (https://ng.ant.design/docs/introduce/zh) 第一类:嵌套表单 1. 静态表单嵌套 demo.component.html & ...

  5. 了解HTML表单之form元素

    前面的话 表单是网页与用户的交互工具,由一个<form>元素作为容器构成,封装其他任何数量的表单控件,还有其他任何<body>元素里可用的标签 表单能够包含<input& ...

  6. form表单那点事儿(上) 基础篇

    form表单那点事儿(上) 基础篇 做为html中最为常见,应用最广泛的标签之一,form常伴随前端左右.了解更深,用的更顺. 目录: 表单属性 表单元素 常识 模拟外观 表单属性 这个表单展示了fo ...

  7. angular2 学习笔记 ( Form 表单 )

    refer : https://angular.cn/docs/ts/latest/guide/forms.html https://angular.cn/docs/ts/latest/cookboo ...

  8. Alamofire源码解读系列(十一)之多表单(MultipartFormData)

    本篇讲解跟上传数据相关的多表单 前言 我相信应该有不少的开发者不明白多表单是怎么一回事,然而事实上,多表单确实很简单.试想一下,如果有多个不同类型的文件(png/txt/mp3/pdf等等)需要上传给 ...

  9. HTML(七)HTML 表单(form元素介绍,input元素的常用type类型,input元素的常用属性)

    前言 表单是网页与用户的交互工具,由一个<form>元素作为容器构成,封装其他任何数量的表单控件,还有其他任何<body>元素里可用的标签 表单能够包含<input> ...

随机推荐

  1. Presto实战

    一.Presto简介 1.PRESTO是什么? Presto是一个开源的分布式SQL查询引擎,适用于交互式分析查询,数据量支持GB到PB字节. Presto的设计和编写完全是为了解决像Facebook ...

  2. InnoDB中锁的算法(2)

    Ⅰ.上节回顾 session1: (root@localhost) [test]> select * from l; +---+------+------+------+ | a | b | c ...

  3. [Day11]接口、多态

    1.接口 (1)接口定义:interface关键字 ,所在文件仍然是.java文件,编译后仍产生.class文件.       定义格式 public interface 接口名{ 抽象方法1: 抽象 ...

  4. ext 的loadmask 与ajax的同步请求水火不容

    由于ajax 的同步请求会有一段请求时间.有的短.有的长,对于短的我们还是能接受的,不过长的话就必须处理一下了, 就比如处于ext 4.2.0的框架下,需要一个遮掩的样式,框架是有自带的,loadma ...

  5. ZBX_NOTSUPPORTED: Cannot obtain filesystem information: [13] Permission denied

    zabbix有默认两条自动发现规则,其中一条是自动发现已挂载文件系统,但笔者的三个挂载文件系统中两个监控成功了,一个失败 agentd端挂载情况: 仔细研究sdb1的挂载点,发现它是挂载在xiami用 ...

  6. 接口测试工具-Jmeter使用笔记(九:跨线程组传递变量)

    使用场景: 请求API需要授权令牌,但是授权令牌只需要获取一次,即可调用服务器上其他业务接口. 所以我想要把授权操作放在单独的一个线程,业务流放在其他线程. 这就需要我把从授权线程获取的令牌传入业务流 ...

  7. Python3学习之路~5.13 re模块 正则表达式

    re模块用于对python的正则表达式的操作. 常用正则表达式符号 字符数字: . 匹配除换行符以外的任意字符,即[^\n] \s 匹配任意空白符(如\t.\n.\r ) \S 匹配任意非空白符 \w ...

  8. go语言的安装与开发环境

    安装golang编译器: https://studygolang.com/dl 之后设置环境变量GOPATH(项目目录)  GOROOT(默认已经设置好) 安装编辑器:IDEA安装和破解 https: ...

  9. python常用函数及模块

    原文来源于博客园和CSDN 1.计算函数 abs()--取绝对值 max()--取序列最大值,包括列表.元组 min()--取序列最小值 len()--取长度 divmod(a,b)---取a//b除 ...

  10. 027-Session状态提供程序

    Session分三种:1.InProc(进程内)-默认就是这种-速度快/但内存小/易丢失进程外:可以在IIS或ASPNET服务意外关闭时继续保持状态,注意此时存储到session中的对象必须支持序列化 ...