Active Admin - 根据第一个下拉菜单刷新第二个下拉菜单,Ruby on Rails

Posted

技术标签:

【中文标题】Active Admin - 根据第一个下拉菜单刷新第二个下拉菜单,Ruby on Rails【英文标题】:Active Admin - refresh second drop down based on first drop down, Ruby on Rails 【发布时间】:2012-03-23 16:15:58 【问题描述】:

我在 Ruby on Rails 上使用 Active Admin Gem。我有一个表格,其中我选择了类别和子类别,然后我必须填写数据。因此,我在活动管理资源中添加的 sqlite 中创建了两个表。

一切正常,但子类别的下拉菜单并未根据所选类别进行过滤。

我也是 Ruby 和 RoR 的新手。我不知道选择类别后如何刷新子类别的下拉菜单。

我知道我可以通过 AJAX 和 javascript 做到这一点,但我不知道在哪里编写代码?

此外,Active Admin 中是否有任何特定的过滤器可用,无需 ajax 或 javascript 即可实现。

我们将不胜感激任何想法或帮助。

【问题讨论】:

查看railscasts.com/episodes/88-dynamic-select-menus 如果你同意这个答案,你介意接受吗?谢谢 【参考方案1】:

我不知道 Active Admin 中是否有任何特定的过滤器可用,但我通过 3 步方式解决了它(假设类别 - 是房子,子类别 - 是公寓):

第一步:定义包含ajax请求的助手

(当然要在routes.rb中预定义path

#application_helper.rb
def remote_request(type, path, params=, target_tag_id)
  "$.#type('#path',
             #params.collect  |p| "#p[0]: #p[1]" .join(", "),
             function(data) $('##target_tag_id').html(data);
   );"
end

第二步:为:onchange操作添加此方法

#admin/inhabitants.rb (DSL with formtastic)

form do |f|
  f.inputs do
  #...
    f.input :house, :input_html => 
        :onchange => remote_request(:post, :change_flats, :house_id=>"$('#house_id').val()", :flat_id)
    
    f.input :flat
  #...
  end
end

第三步:渲染过滤结果

(你可以渲染部分而不是:text,我决定把它放在一个activeadmin资源文件中)

controller do
  def change_flats
    @flats = House.find_by_id(params[:house_id]).try(:flats)
    render :text=>view_context.options_from_collection_for_select(@flats, :id, :flat_number)
  end
end

【讨论】:

@okliv 我是新手:您能否更明确地说明如何在 routes.rb 上定义路径?谢谢,我已经为此苦苦挣扎了几个小时,您的帖子似乎满足了我的需求! 一年多过去了,我不记得它到底是怎么回事,但它必须类似于post '/change_flats' =>'houses#change_flats' - 路由到houses_controller.rb 中的change_flats 方法.. 或者您可以定义AA 自定义操作activeadmin.info/docs/8-custom-actions.html 在资源或集合上,具体取决于您的自定义案例。如果您提出这样的问题并指出我的问题 - 我会尝试直接帮助您解决这个问题 @okliv 非常感谢。我会试试看。我在这里添加了一个问题***.com/questions/20034892/…:令我惊讶的是,我没有使用 formtastic :as =>:select 或 Collection 来获得由我创建的输入填充的 2 下拉列表。 @okliv 你能看看***.com/questions/28187354/… 这样做时,我遇到了一个问题,:house_id=>"$('#house_id').val()" house_id 被传递,因为它是 $('#house_id').val()",而不是被获取和传递的值..【参考方案2】:

我做到了这一点,就像任何从事 Rails 项目的非 Rails 开发人员一样 - 快速而肮脏。方法如下:

#...
f.input :user, :input_html => 
  :onchange => "
    var user = $(this).val();

    $('#order_location_id').val(0).find('option').each(function()
      var $option = $(this),
        isCorrectUser = ($option.attr('data-user') === user);  

        $option.prop('disabled',!isCorrectUser);
    );
  "

f.input :location, collection: Location.all.map |loc|
  [loc.name,loc.id, "data-user" => loc.user_id]

#...

不需要 AJAX。请注意,这不会删除不需要的选项,它只是禁用它们(对于我的场景来说足够了)。这可以很容易地用一个助手模块化,但我真的只需要这个功能一次。

【讨论】:

【参考方案3】:

对于遇到同样问题的其他人,请查看此railscast

我遇到了同样的问题here

这是我在 activeadmin 中实现多个动态选择菜单的方法:

config/initializers/active_admin.rb

  config.register_javascript 'exam_registrations.js.coffee'

app/admin/exam_registrations.rb

  form do |f|
    f.inputs "Exam Registration Details" do
      f.input :user_id, :label => 'Teacher', :as => :select, :collection => User.where(:admin => 'false', :active => true).order(:name), :include_blank => true
      f.input :student_id, :hint => 'Students grouped by teacher names', :as => :select, :collection => option_groups_from_collection_for_select(User.where(:admin => false, :active => true).order(:name), :students, :name, :id, :name)
      f.input :lesson_id, :hint => 'Lessons grouped by student names', :as => :select, :collection => option_groups_from_collection_for_select(Student.where(:active => true).order(:name), :lessons, :name, :id, :name)
    end
    f.buttons
  end

app/assets/javascripts/exam_registrations.js.coffee

#first menu    
jQuery ->
      $('#exam_registration_student_id').parent().hide()
      students = $('#exam_registration_student_id').html()
      $('#exam_registration_user_id').change ->
        user = $('#exam_registration_user_id :selected').text()
        escaped_user = user.replace(/([ #;&,.+*~\':"!^$[\]()=>|\/@])/g, '\\$1')
        options = $(students).filter("optgroup[label='#escaped_user']").html()
        if options
          $('#exam_registration_student_id').html(options)
          $('#exam_registration_student_id').parent().show()
        else
          $('#exam_registration_student_id').empty()
          $('#exam_registration_lesson_id').empty()

# second menu
  $('#exam_registration_lesson_id').parent().hide()
  lessons = $('#exam_registration_lesson_id').html()
  $('#exam_registration_student_id').click ->
    student = $('#exam_registration_student_id :selected').text()
    escaped_student = student.replace(/([ #;&,.+*~\':"!^$[\]()=>|\/@])/g, '\\$1')
    options = $(lessons).filter("optgroup[label='#escaped_student']").html()
    if options
      $('#exam_registration_lesson_id').html(options)
      $('#exam_registration_lesson_id').parent().show()
    else
      $('#exam_registration_lesson_id').empty()

重新启动服务器,菜单开始工作!

【讨论】:

【参考方案4】:

现在可以使用这个 gem https://github.com/holyketzer/activeadmin-ajax_filter,在你的表单代码中使用这样的代码:

f.input :category_id, as: :select # ...
f.input :subcategory_id, as: :ajax_select, data:  
  ajax_search_fields: [:category_id], 
  search_fields: [:subcategory_atrribute], 
  url: '/admin/subcategories/filter' 

在你的子类别资源页面中:

ActiveAdmin.register Subcategory do
  include ActiveAdmin::AjaxFilter
  # ...
end

不要忘记包含资产

【讨论】:

【参考方案5】:

你也可以使用activeadmin_addons gem Nested Select

【讨论】:

【参考方案6】:

dependent-select 也是一个不错的选择

【讨论】:

以上是关于Active Admin - 根据第一个下拉菜单刷新第二个下拉菜单,Ruby on Rails的主要内容,如果未能解决你的问题,请参考以下文章

在activeadmin中排序父菜单项

在Active Admin Rails中创建新项目时过滤下拉列表

根据第一个选择动态填充第二个下拉菜单

根据第一个和第二个菜单选择填充第三个下拉菜单

根据 DJango/Ajax 中的第一个选定下拉菜单创建下拉选择

如何根据另一个下拉菜单值禁用下拉菜单