概述/模型

例如,假设您有一个相当大的系统,其中包含非常通用的模型(我们将在此示例中使用三个)

  • 位置(通用地址字段、类型、line1、line2、towncity 等)
  • 公司(通用公司字段、类型、名称等)
  • 联系人(通用联系人字段、tpye、姓名、职位等)

  • 示例(+ rails_admin 截图)

    我发现在制作这样的系统时,我总是遇到同样的问题。例如,我单击了公司上的添加按钮(所以我现在已经加载了部分表单等),我在添加公司的过程中发现我需要的位置不在系统中。我想快速打开一个模态窗口,添加位置,然后通过 jquery 或类似的东西更新选择。太棒了,没什么太难的,它已经在 rails_admin 之类的系统中完成了(见下面的截图):

    http://www.server1-breakfrom.com/nestedaddexample.jpg

    在处理一层嵌套时,这一切都很好,一般来说,将这种情况作为稀有情况处理时,一切都很好(因为您可以随时在能力中进行编程)。但是,我正在做一个系统,它本身几乎需要成为一个框架,因为我在超过 50% 的模型中都需要它。我需要能够在模型/ Controller 中动态添加各种​​选项,并让表单动态生成相关按钮。

    其他问题
  • 模态内/之上的模态 - 添加联系人时,您单击以添加他们的公司,在此新公司中添加表单,然后您要添加一个位置:boom,模态在模态之上。
  • jquery 附加到选择的什么文本 - 您需要知道如何更新选择元素并可能在屏幕上找到所有相关的选择元素。添加公司将使用它的 ID 和它的名称,但位置可能需要使用 ID 以及文本的 line1、line2 和 towncity。
  • 模式中的验证(但我假设我们可以使用某种 jquery,因为我们已经非常依赖它了)

  • 扩展问题

    所以,除了问题:我是不是把事情复杂化了,有没有容易解决的问题(我必须强调这 3 个模型纯粹是示例,例如我有很多模型需要引用一家公司,这不仅仅是一个联系人,因此“只需根据需要对其进行编程”,就行不通了!)。

    或者,我应该拆开 rails_admin 并取出我需要的部分吗? (同样,他们还没有解决多重嵌套问题,所以我觉得从头开始可能会更好?)。

    最佳答案

    我遇到了类似的情况。我的解决方案可能在您的场景中存在性能问题,但对我来说没有,但它是一个低并发使用系统,只有 300 个总用户。

    我所做的是使用一个 MEGA AJAX View /表单!并根据需要使用 JavaScript 显示/隐藏。这种技术要求您不要使用表单标签助手(即 text_field_tag 而不是 f.text_field),您必须控制元素名称。

    因此,开始使用您最终需要的所有表单创建一个 View 。您必须区分它们,因此将每个放在具有唯一 ID 的 div 元素中。

    <%= form_for @mega, :remote=>true do %>
      <div id='main_part'>
        <%= render :partial => "main_part", :object=>@mega  %>
      </div
      <div id='subpart1'>
        <%= render :partial => "subpart1" , :object=>@foobar , :locals=>{:id=>@foobar.id} %>
      </div
      <div id='subpart2'>
        <%= render :partial => "subpart2" , :object=>@barfoo , :locals=>{:id=>@barfoo.id} %>
      </div
    <% end %>
    

    表单部分示例,注意区分提交按钮:
    <%= label_tag "main_part[name]" ,"Name" %>
    <%= text_field_tag "main_part[name]" , main_part.name %>
    <%= submit_tag "UPDATE", :name=>'main_part' %>
    
    <%= hidden_tag_field "subpart1_id" , id %>
    <%= label_tag "subpart1[city]" ,"City" %>
    <%= text_field_tag "subpart1[city]" , subpart1.city%>
    <%= submit_tag "ADD", :name=>'subpart1' %>
    

    所以现在你需要一个大型 Controller ,因为这个表单发布到单个 Controller 操作。这个 Controller 看起来只是你的顶级模型的常规 Controller ,但它需要为所有模型做家务。

    该 Controller 操作必须确定单击了哪个提交按钮,即
    def update
      if params[:main_part]
        # since I controlled the parameter naming I know what's in params[:main_part]
        # which is main_part[:name]
        @mega = MainThing.find(params[:id])
        @mega.attributes = params[:main_part]
        @mega.save
        # only for main_part is the id valid,  in every other case you have to
        # manually extract the id
      elsif params[:subpart1]
        @subpart1_id = params[:subpart1_id]
        @foobar = FooBar.find(@subpart1_id)
        @foobar.attrubutes = params[:subpart1]
        @foobar.save
      else
      end
    end
    

    由于大型表单是 remote=>true,您需要创建一个 javascript 文件来重新加载所有表单部分,因此在 app/views/megas/update.js.erb 中:
    $('#main_part').html('<%= escape_javascript(render :partial=> "main_part", :object=>@mega) %>');
    $('#subpart1').html('<%= escape_javascript(render :partial=> "subpart1", :object=>@foobar :locals=>{:id=>@foobar.id) %>');
    

    现在这里是性能问题出现的地方。如果您注意到,如果我运行该 javascript,它将期望定义所有这些实例变量,因此各种部分将呈现刷新任何因更新而获得新值的选择标签.在我的情况下,我只是在前置过滤器中将它们全部加载,即
    class MegaController < ApplicationController
      before_filter :load, :only=>[:edit]
      def load
         @mega = Mega.find(params[:id])
         @foobar = @mega.foobar
         @barfoo = @foobar.barfoo
      end
    

    但是您也可以不这样做,而是创建单独的 javascript 文件并在 Controller 中专门呈现它们,即
    def update
      if params[:main_part]
        # do whatever...
        render :action=>'update_set1', :handler=>[:erb], :formats=>[:js]
      elsif params[:subpart1]
        # do whatever
        render :action=>'update_set1', :handler=>[:erb], :formats=>[:js]
      elsif params[:subpart2]
        # do whatever
        render :action=>'update_set2', :handler=>[:erb], :formats=>[:js]
      end
    end
    

    文件 app/views/mega/update_set1.js.erb 只会更新受@mega 或@foobar 更新影响的部分,update_set2.js.erb 会更新受@barfoo 更新影响的部分。

    最后一点,你的表单是remote=>true,你如何退出?假设你有:
    <%= submit_tag 'Cancel', :name=>'cancel' %>
    

    然后在 Controller 中你会做这样的事情:
     def update
       if params[:cancel]
          render :js=> "window.location = '/'"
       else
          # whatever....
       end
     end
    

    最后一步是添加 javascript 以根据需要显示/隐藏表单 div,这是留给读者的练习....

    更新
    class Mega < ActiveRecord::Base
       def self.get_param_name
          self.class.name
       end
    
       def self.get_id_name
          "#{self.class.name}_id"
       end
    end
    
    class MyModel < Mega
    end
    

    然后在大型 Controller 中:
    def edit
       @mymodel = MyModel.find(params[MyModel.get_id_name])
    end
    

    10-08 04:50