• 嵌套表单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. The way to unwind the stack on Linux EABI

    I. probe the stack frame structure The original idea is to unwind the function call stack according ...

  2. 单片机小白应该如何学习stm32的一些实践心得!

    嵌入式搬砖道路上的大三狗一枚,撑死算个初学者吧.才学有限,下面仅仅是本人对STM32学习的一点心得与建议,希望对题主有帮助吧. 心得:本人当初学习STM32的时候有一些跟风的因素,自以为学的芯片越多就 ...

  3. React-Router4.x中文文档

    以下为翻译的中文API(水平有限,凑合看,欢迎纠正补充~) <BrowserRouter> 使用HTML5历史记录API(pushState,replaceState和popstate事件 ...

  4. java之xml解析-dom4j

    解析方式 XML 解析方式有很多种,但是常用的有两种,如下: DOM Document Object Model:把整个 XML 读到内存中,形成树状结构.整个文档为 Document 对象,属性为 ...

  5. 认识拨号计划-dialplan

    拨号计划是 FreeSWITCH 中至关重要的一部分.它的主要作用就是对电话进行路由(从这一点上来说,相当于一个路由表).说的简明一点,就是当一个用户拨号时,对用户所拨的号码进行分析,进而决定下一步该 ...

  6. vue 环境报错 chromedriver@2.44.1 install: `node install.js`

    解决办法: 1. yarn add chromedriver -g 2.yarn add chromedriver --chromedriver_cdnurl=http://cdn.npm.taoba ...

  7. A标签中 href 和 onclick用法、区别、优先级别

    (内容摘自:https://blog.csdn.net/chenchunlin526/article/details/77346049) Html A标签中 href 和 onclick 同时使用的问 ...

  8. UDAF(用户自定义聚合函数)求众数

    除了逐行处理数据的udf,还有比较常见的就是聚合多行处理udaf,自定义聚合函数.类比rdd编程就是map和reduce算子的区别. 自定义UDAF,需要extends org.apache.spar ...

  9. 关于angular2 打包(一)

    在讲到angular2 及以上项目打包之前,我先讲一下.angular cli 拥有自己的打包工具,熟悉的可以直接上手.如果用不惯,也可以去使用webpack 之类的.内置的systemjs也是很好用 ...

  10. org.codehaus.plexus.archiver.jar.Manifest.write(java.io.PrintWriter)

    通过start.spring.io下载maven工程导入eclipse后,出现pom文件错误: org.codehaus.plexus.archiver.jar.Manifest.write(java ...