4

概要・機種

たとえば、非常に一般的なモデルを持つかなり大規模なシステムがあるとします (この例では 3 つを使用します)。

  • 場所 (一般的な住所フィールド、タイプ、line1、line2、towncity など)
  • 会社 (一般的な会社フィールド、種類、名前など)
  • 連絡先 (一般的な連絡先フィールド、TPYE、名前、役職など)

例 (+ rails_admin のスクリーンショット)

このようなシステムを作るとき、私はいつも同じ問題に遭遇します。たとえば、会社の追加ボタンをクリックすると (フォームの一部などを読み込んだので)、会社を追加する途中で、必要な場所がシステムにないことがわかりました。モーダルウィンドウをすばやく開き、場所を追加してから、jquery またはそれらの行に沿って何かを介して選択を更新したいと考えています。これは、rails_admin などのシステムで実行されています (下のスクリーンショットを参照)。

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

これは、ネストの 1 つのレベルを処理する場合はすべて適切であり、一般的に言えば、これをレアリティとして処理する場合はすべて適切です (as および when でアビリティをプログラムできるため)。ただし、モデルの 50% 以上で必要なため、これ自体がほとんどフレームワークである必要があるシステムを実行しています。モデル/コントローラーにさまざまなオプションを動的に追加し、フォームに関連するボタンを動的に生成させる機能が必要です。

その他の問題

  1. モーダル内/モーダルの上にあるモーダル - 連絡先を追加するときに、クリックして会社を追加します。この新しい会社内にフォームを追加してから、場所を追加します: ブーム、モーダルの上にモーダル。
  2. jquery で select に追加するテキスト - select 要素を更新する方法と、関連するすべての select 要素を画面上で見つける方法を知る必要があります。会社を追加すると、その ID と名前が使用される可能性がありますが、場所では ID を使用する必要があり、テキストには line1、line2、towncity などを使用する必要があります。
  3. モーダル内での検証 (ただし、すでに jquery に大きく依存しているため、ある種の jquery を使用できると思います)

質問の拡大

それで、質問に加えて:私は物事を複雑にしすぎていますか、そして私の問題を解決するのは簡単ですか(3つのモデルは純粋に例であることを強調しなければなりません.連絡先なので、「必要に応じてプログラムするだけ」では機能しません!)。

それとも、rails_admin をバラバラにして、必要な部分だけを取り出す必要がありますか? (繰り返しますが、彼らは複数のネストの問題を解決していないので、最初から始めたほうがよいのではないでしょうか?)。

4

2 に答える 2

2

私は同様の状況に直面しました。私のソリューションには、シナリオでパフォーマンスの問題がある可能性がありますが、私にはありませんでしたが、同時使用率が低く、合計ユーザー数が 300 しかありません。

私がしたことは、1 つの MEGA AJAX ビュー/フォームを使用することでした! 必要に応じて JavaScript を使用して表示/非表示を切り替えます。この手法では、フォーム タグ ヘルパー (つまり、f.text_field の代わりに text_field_tag) を使用せず、要素名を制御する必要があります。

したがって、最終的に必要になるすべてのフォームを含む単一のビューを作成することから始めてください。それらを区別する必要があるため、それぞれを一意の 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' %>

この 1 つのフォームが 1 つのコントローラー アクションに投稿されるため、メガ コントローラーが必要になります。このコントローラーは、最上位モデルのみの通常のコントローラーのように見えますが、すべてのモデルのハウスキーピングを行う必要があります。

そのコントローラーアクションは、どの送信ボタンがクリックされたかを把握する必要があります。

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 ファイルを作成する必要があります。

$('#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 ファイルを作成し、コントローラーで具体的にレンダリングすることもできます。

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' %>

次に、コントローラーで次のようにします。

 def update
   if params[:cancel]
      render :js=> "window.location = '/'"
   else
      # whatever....
   end
 end

最後のステップは、必要に応じてフォーム div を表示/非表示にする JavaScript を追加することです。

アップデート

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

次に、メガコントローラーで:

def edit
   @mymodel = MyModel.find(params[MyModel.get_id_name])
end
于 2013-02-24T19:50:21.203 に答える
1

問題を解決する

After a lot of testing and going through the code kindly submitted by RadBrad, I accidentally stumbled across a Gem with an answer to almost exactly what I expected from the question/phrase 'dynamic nested forms (with jQuery)'. 'Unlimited', it seems, was a poor choice of word for the original question but hopefully this text will get the question picked up a bit better on the search engines.

The Gem

That Gem is called Cocoon and can be found here: https://github.com/nathanvda/cocoon

Extras

As a bonus it is built using jQuery, compatible with simple_form, formtastic and also fits quite well into Twitter Bootstrap!

Additional Notes

I've not fully tested it and to be brutally honest, validation already looks to be a minor issue but I will update this answer further if I find anything that doesn't work as expected.

The example github projects provided by Cocoon are pretty outdated and you'll need to do a lot of re-jigging in the Gem file to get them to work (but it is do-able!). Rest assured the main Gem (at the time of writing this) is up-to-date.

于 2013-02-26T21:07:40.467 に答える