【问题标题】:Rails Dynamically Changing Collection Select In Form Based on form fieldRails根据表单字段动态更改表单中的集合选择
【发布时间】:2014-10-21 10:19:07
【问题描述】:

我有一个跟踪呼叫的 Rails 3.2.14 应用程序,每个呼叫都有一个来自 Facility 模型的接送设施,这是一个关联。

在呼叫模型中,区域模型(即休斯顿、达拉斯、奥斯汀等)有一个关联,我们根据呼叫的来源选择一个区域。

我想做的是能够选择一个特定的地区(即休斯顿),并在取货设施集合中只显示休斯顿地区的设施。

我假设一开始我需要在 Facility 和 Region 之间建立这样的关系:

facility.rb

attr_accessible :region_id
belongs_to :region

region.rb

has_many :facilities

然后我需要为每个设施设置一个与相应区域(即休斯顿、达拉斯等)匹配的 region_id,以便关联正常工作。

我不确定如何选择特定区域,并且仅在表单中显示该区域中的设施。我假设我会在这里使用一些 jQuery/JS/Ajax 来实现它,但不知道如何让它工作。

以下是我目前的呼叫、设施和区域模型的摘录:

call.rb

belongs_to :transferred_from, :foreign_key => :transfer_from_id, :class_name => 'Facility'
belongs_to :transferred_to, :foreign_key => :transfer_to_id, :class_name => 'Facility'
belongs_to :region

facility.rb

has_many :calls_transferred_from, :foreign_key => :transfer_from_id, :class_name => 'Call'
has_many :calls_transferred_to, :foreign_key => :transfer_to_id, :class_name => 'Call'

region.rb

has_many :calls

这是我的调用表单部分的摘录:

_form.html.erb

<%= form_for(@call) do |f| %>
  <%= f.label :region %>
  <%= f.collection_select(:region_id, Region.all, :id, :area, {:include_blank => true}, {:class => 'select', required: true}) %>
  <%= f.label :Transfer_From %>
  <%= f.collection_select(:transfer_from_id, Facility.active.order("facility_name ASC"), :id, :facility_name, {:include_blank => true}, {:class => 'select'}) %>
 <%= f.button "Submit", class: 'btn btn-info btn-large', data: {disable_with: "<i class='icon-spinner'></i>Processing..."} %> 
<% end %>

如果其中任何内容令人困惑或需要澄清,请告诉我。总而言之,我正在尝试选择一个地区(休斯顿),并仅在选择该地区时在表单中显示休斯顿地区的设施。

提前感谢您提供的任何帮助或提示。

【问题讨论】:

  • 我认为Railscast:Dynamic Select Menus 可能是朝着正确方向迈出的一步,但我不确定我是否会使用 grouped_collection_select。
  • 我已经设置了 Region 和 Facility 之间的关联,并且该部分工作正常,现在只需要找出一些 jQuery/CoffeeScript 来实现这一点,以及在我的表单中使用什么方法来选择。 grouped_collection_select 似乎没有做我需要的事情。

标签: jquery ruby-on-rails-3 forms activerecord collections


【解决方案1】:

基于 Railscasts 动态选择菜单,我提出了以下建议:

calls.js.coffee

jQuery ->
  facilities = $('#call_transfer_from_id').html()

  $('#call_region_id').change ->
    region = $('#call_region_id :selected').text()
    options = $(facilities).filter("optgroup[label=#{region}]").html()

    if options
      $('#call_transfer_from_id').html(options)   
    else
      $('#call_transfer_from_id').empty()

_form.html.erb

<%= f.grouped_collection_select :transfer_from_id, Region.order(:area), :facilities, :area, :id, :facility_name, {include_blank: true}, class: 'select' %>

上述 grouped_collection_select 的问题在于它调用 :facilities 列出了所有设施,我需要调用 Facility.active 的等效项(我在 Facility 上创建的范围仅列出活动设施)。如何从 grouped_collection_select 中调用它?

到目前为止,在新呼叫中,我能够选择区域,然后该区域的设施仅显示在 from 字段中(调用 transfer_from_id)。在编辑呼叫并尝试更改设施时,我会看到按地区分组的完整设施列表,而不仅仅是该地区的设施。如果我想缩小范围,我必须更改区域,然后将其更改回原始区域,以便特定区域的设施仅显示。

我认为我在这方面取得了进展,但它并没有按照我想要的方式进行。我非常愿意接受更有意义、更清晰的答案。

【讨论】:

  • 啊,好吧,我喜欢这里的答案,因为它比我写的更干净:)
  • 谢谢,它大部分都在工作,但我仍在试图弄清楚如何在 grouped_collection_select 帮助器中调用 Facility.active。它只让我通过 :facilities 返回所有设施。
  • 啊,您可以通过在 Region 类中设置一个方法来解决这个问题。 def active_facilities; self.facilities.active; end; 然后不是 :facilties,而是 :active_facilities
  • @agmcleod 使用这种方法似乎已经解决了我的问题。花了我一秒钟来弄清楚为什么我要在 Region 模型中编写一个方法,但它是一个关联并且现在很有意义区域并切换回来以获取有限列表。 :) 取得进展。哇!
  • 基本上,视图方法所做的就是获取符号,并在对象上调用发送。这是您可以元编程方法调用的方式。类似于 javascripts 的 call()
【解决方案2】:

对于这样的事情,我通常通过在客户端加载字典来保持简单,然后引用它。

因此,在您看来,您可以构建如下内容:

<script>
  var facilitiesForRegion = {};
  <% Facility.all.each do |facility| %>
    var region = facilitiesForRegion[<%= facility.region_id %>];
    var object = { id: <%= facility.id %>, name: '<%= facility.facility_name %>'};
    if (region) {
      region.push(object);
    }
    else {
      facilitiesForRegion[<%= facility.region_id %>] = [object];
    }
  <% end %>

  $("#call_region_id").on("change", function (e) {
    var id = parseInt($(this).val());
    var facilities = facilitiesForRegion[id];
    $('#call_transfer_from_id').children().remove();
    for (var i = 0; i < facilities.length; i++) {
      $('#call_transfer_from_id').push('<option value="'+ facilities[i].id +'">'+ facilities[i].name +'</option>');
    }
  });
</script>

有点丑。我不是最喜欢在这样的视图中构建数据数组的人,但它可以工作并且避免等待 ajax 请求。

请务必仔细检查下拉菜单的 ID。我是根据字段名称和 for_for 猜测的。

【讨论】:

  • 感谢您的快速回复。我已经把它放在我的 _form.html.erb 视图中,到目前为止还没有运气。当我选择一个区域时,设施不会更改为特定区域的设施。
  • 是在你的表格之后吗?您的 javascript 控制台中是否出现任何错误? (检查 firebug/chrome 开发工具)。也尝试调试,在更改事件中设置断点,看看情况如何。
  • 我在 form_for 声明之前就有了。应该是后吗?我在 Chrome 中检查了控制台,到目前为止我没有看到任何 JS 错误或问题。我还发布了一个我能够开始工作的答案,但这并不是我真正想要的。再次感谢您的帮助!
  • 是的,应该在之后,或者将代码包装在一个document.ready中。 dom 元素必须存在才能将事件绑定到它们。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-22
  • 1970-01-01
  • 2020-09-03
  • 2016-10-04
  • 2015-09-09
相关资源
最近更新 更多