Rails表单中的下拉菜单和常量的使用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Rails表单中的下拉菜单和常量的使用相关的知识,希望对你有一定的参考价值。

参考技术A 如图需求:

我们需要新增一个字段叫“用户状态”,其中有两种状态,分别为“使用”和“不使用”。

1)明确这是业务层面的需求,要放在model中进行常量设定。2)制作下拉菜单,进行选择,然后创建数据。3)在特定的页面显示结果。

一、明确这是业务层面的需求,要放在model中进行常量设定。
“用户状态”这个字段属于用户的属性,所以在user的model中定义。在user.rb中插入:

解释:
use和no_use为两个哈希的key,使用和不使用为value。
freeze方法把这个哈希固定住,无法修改。这都可以在rails c中进行测试。

二、制作下拉菜单,进行选择,然后创建数据。

其中,:status为字段名。
User::STATUS为路径,表示到Use的rmodel中找STATUS常量。
invert方法,把常量中的key和value进行调换,这样在页面中就出现“使用”和“不使用”,而不会显示key中的“use”和“no_use”。

三、在特定的页面,如index中,显示结果。

带有 jQ​​uery 的 Rails 中的动态下拉(选择框)菜单不可逆

【中文标题】带有 jQ​​uery 的 Rails 中的动态下拉(选择框)菜单不可逆【英文标题】:A dynamic dropdown (selectbox) menu in Rails with jQuery is not reversible 【发布时间】:2021-09-17 07:43:33 【问题描述】:

在由 Rails 6.1 控制的网站表单上,我想实现“动态”或级联下拉菜单,以便第二个下拉菜单中的选项根据第一个下拉菜单中的所选项目而有所不同。

具体来说,我有一个与CountryTown 模型相关联的Person 模型。关系是Personbelongs_toTown,其中belongs_toCountryhas_many 中。定义了方法Country#nameTown#name。在createPerson 的网站上的 表单中,用户首先从下拉菜单(选择框)中选择国家,然后选择城镇 在第二个下拉菜单中。

我基本上遵循了#88 Dynamic Select Menus (revised) 的过程,但在标准 jQuery 中重写了它,而不是在 Railcasts 中使用 Coffee。

简而言之,我使用 Rail 的 form.grouped_collection_select 辅助方法为城镇创建了一个选择框;生成的 HTML 中的部分包含许多OPTGROUP,每个都对应一个国家,其中有多个子城镇belongs_to。关联的 jQuery 脚本过滤第二个(即,Town)下拉菜单,将 Country 下拉菜单中的选定项目与每个 OPTGROUPLABEL 进行比较城镇下拉菜单(选择框)。

它有点工作,但有一个严重的缺陷。基本上,它在第一次点击时起作用。然而,一旦用户改变主意并重新选择不同的国家城镇的所有选项都会消失。换句话说,用户的第一选择是不可逆的。这是一个糟糕的界面。

如何解决这个问题,让用户的选择总是可逆的?

下面是表单视图(hrb.erb)和Javascript jQuery代码中的相关部分。这里,person 是模型Person 的一个新实例。它使用 Rails 6.1.4、Ruby 3.0.1 和 jQuery 3.5.1 进行了测试。

erb.html 用于表单

<%= form_with(model: person, local: true) do |form| %>
  <div class="field">
    <%= form.label 'town_id.country_id', 'Country'%>
    <%= form.collection_select town_id.country_id', Country.all,
        :id, :name, include_blank: true %>
  </div>

  <div class="field">
    <%= form.label 'place.town_id' %>
    <%= form.grouped_collection_select 'place.town_id', Country.all,
        :towns, :name, :id, :name, include_blank: true %>
  </div>
<% end %>

Javascript jQuery

 var contsel = "#"+$.escapeSelector('person_place.town_id.country_id');
 $(contsel).change(function()
   var prefsel = "#"+$.escapeSelector('person_place.town_id');
   var contsel = "#"+$.escapeSelector('person_place.town_id.country_id');
   var country = $.escapeSelector($(contsel+' :selected').text());
   var towns = $(prefsel).html();
   var options = $(towns).filter("optgroup[label='"+country+"']").html();
   if (options) 
     $(prefsel).html(options);
    else 
     $(prefsel).empty();
   
 )

【问题讨论】:

【参考方案1】:

有很多方法可以使用 Web 应用程序框架来实现动态下拉菜单。至于使用 Rails 的方式, this question 的答案似乎总结得特别好。

我认为 OP 使用基于 OPTGROUP 标签的 jQuery 的方式有一些优点,如果无论如何都不是没有缺点的话,

    Rails 端编码最少, 即使禁用了 Javascript,用户也可以制定(并提交)有意义的选择(好吧,谁会?)。

OP 的 Javascript 代码使生成的 HTML 不可逆,因为它使用 filter() 方法破坏性地修改 HTML。在用户选择提示change()的第一个动作时,HTML被不可逆地修改。例如,一旦选择了 Country=Australia,就 Javascript 代码而言,除了澳大利亚以外的所有 城镇 的内容都将被删除。因此,由于任何后续操作都将基于修改后的 HTML,因此 Javascript 代码对任何其他国家/地区的城镇一无所知。

下面的 Javascript jQuery 代码应该可以解决这个问题,使用户的选择是可逆的。它基于 OP 的示例代码,前半部分相同,只是增加了两行。

$(function()
 var contsel = "#" + $.escapeSelector('person_place.town_id.country_id');
 var townsel = "#" + $.escapeSelector('person_place.town_id');
 $(townsel).parent().hide();
 $(contsel).change(function() 
   var townsel = "#" + $.escapeSelector('person_place.town_id');
   var contsel = "#" + $.escapeSelector('person_place.town_id.country_id');
   var country = $.escapeSelector($(contsel + ' :selected').text());
   var towns = $(townsel).html();
   var options = $(towns).filter("optgroup[label='" + country + "']").html();
   if (options) 
     $(townsel).parent().show();
     $(townsel).show();
     $(townsel + " optgroup").hide();
     $(townsel + " optgroup[label='" + country + "']").show();
     $(townsel).find('option:selected').prop("selected", false);
    else 
     $(townsel).hide();
     $(townsel).parent().hide();
   
 )
)

这里有几点需要注意:

    主要区别在于 hideshow,这取决于用户的选择,并且永远不会删除或修改 HTML 中的任何其他部分。 为了使操作可逆,这明确的show 部分可能已被隐藏。 当所选的国家/地区 em>没有 Towns EM>或NO 国家/ / em>已经隐藏了城镇的整个选择框已选中。change() 发生时,即当用户选择一个新的国家 时,用户之前的选择(如果存在)将被清除。如果没有这个,从技术上讲,用户可以使用相互矛盾的组合(例如 Country=Australia 和 Town=Nairobi)提交表单数据。

这是用于实验的示例代码的jsfiddle。完整代码也可在at Github Gist 获得。

【讨论】:

以上是关于Rails表单中的下拉菜单和常量的使用的主要内容,如果未能解决你的问题,请参考以下文章

Ruby on Rails 表单添加带有文本框的“其他”选项以选择下拉菜单

导航栏中的下拉菜单在 Rails 6 中不起作用

引导表分页下拉菜单不起作用 - Rails

Bootstrap 下拉菜单不与新的 Rails 布局切换

Rails + JQuery 侧边栏下拉菜单立即关闭

React 表单中的两个下拉菜单