Doorkeeper中复选框Scopes参数传递最佳实践及实现方案咨询
我来帮你梳理下这个问题的解决方案,核心就是让表单提交的参数格式和Doorkeeper控制器期望的匹配上,同时保持代码的优雅性。
首先你当前的代码生成的是doorkeeper_application[scopes][foo]这种哈希结构的参数,但Doorkeeper的控制器期望scopes参数是数组或者逗号分隔的字符串(因为Doorkeeper的Application模型默认把scopes存在一个字符串字段里,用逗号分隔),参数格式不匹配自然无法正确接收。
下面是两种最佳实践方案:
方案一:调整复选框name属性,配合模型层处理参数转换
先修改表单代码,把复选框的name改成doorkeeper_application[scopes][],这样提交时会生成数组格式的参数:
<%= f.label :scopes, class: 'col-sm-2 control-label' %> <% Doorkeeper.configuration.scopes.each do |scope| %> <%= check_box_tag("doorkeeper_application[scopes][]", scope, @application.scopes.include?(scope)) %> <%= scope %><br> <% end %>
接下来把数组转换成Doorkeeper需要的逗号分隔字符串,推荐在模型层处理,这样控制器逻辑更干净:
# app/models/doorkeeper/application.rb class Doorkeeper::Application < ApplicationRecord # 覆盖scopes的setter方法,自动处理数组转字符串 def scopes=(value) if value.is_a?(Array) super(value.join(',')) else super end end end
最后在控制器的参数强校验里允许数组类型的scopes:
# app/controllers/oauth/applications_controller.rb def application_params params.require(:doorkeeper_application).permit(:name, :redirect_uri, scopes: []) end
这样提交后,模型会自动把数组转成逗号分隔的字符串,完美适配Doorkeeper的存储格式。
方案二:用Rails的collection_check_boxes简化代码
Rails提供的collection_check_boxes表单辅助方法,可以更简洁地生成复选框列表,还能自动生成正确的数组参数格式:
<%= f.label :scopes, class: 'col-sm-2 control-label' %> <%= f.collection_check_boxes :scopes, Doorkeeper.configuration.scopes, :to_s, :to_s do |builder| %> <%= builder.check_box %> <%= builder.label %><br> <% end %>
这段代码和方案一的效果完全一致,生成的复选框name是doorkeeper_application[scopes][],配合上面模型层的scopes=方法,就能自动完成参数转换。
补充:为什么原来的方式不行?
你之前的代码生成的参数是类似doorkeeper_application[scopes] => {"foo"=>"foo", "bar"=>"bar"}的哈希结构,而Doorkeeper的控制器期望的是数组或字符串,所以参数强校验时会忽略这个哈希,导致无法正确接收选中的scopes。
内容的提问来源于stack exchange,提问作者Gregology

