1

Okay, first and foremost, I am doing something very complicated. It's possible I've gone in a wrong direction.

What I currently have is a STI inheritance model, StateDescription. Subclasses of StateDescription describe a specific state I could care about, such as "LocationHasItem" or "ItemNearOtherItem" or what not.

I understand that I may eventually want to upgrade this to a multi-table inheritance model, as not all subclasses of StateDescription use all possible variables (though there is a high degree of overlap).

These StateDescriptions are owned by another class in a "has_many/belongs_to" relationship.

So, inside the form for this other class, I have:

<%= f.fields_for :conditions do |e| %>  
        <br> 
        <%= render :partial =>"/state_descriptions/form", :locals => {:e => e, :universe => @story_section.universe, :div_id => "condition"}%>
        <Br>
      <% end %>

The StateDescription itself checks for which type it should render, then renders the appropriate partial like so (only showing one subclass, for clarity's sake):

<div id="<%=div_id%><%=e.object.id%>">
          <li>
            <%= e.select(:type, StateDescription.subclasses.collect{|x| x.to_s}) %>

            <br>
            <%= e.label "Inverted?" %>
            <%= e.check_box :invert %>
            <Br>
        <% if e.object.type.to_s == "StateDescription::ItNear" %>
           <%= render :partial =>"/state_description/it_nears/form", :locals => {:e => e, :universe => universe, :div_id => div_id}%>
        <% end %>
            <% end %>

            </li>
  </div>

The subclass partial looks like:

<%=e.collection_select 'item_id', universe.items, :id, :title%>
<%= e.object.title_middle_fragment%>
<%=e.collection_select 'item2_id',universe.items, :id, :title%>

Thus the form starts out the same for all subclasses, and only differs as required.

This works PERFECTLY and I was very happy with it...until I decided I wanted to have ajax update the webpage with the correct form when the sublclass is chosen out of select input field.

Then I realized I couldn't pass the form helper reference ("e" in this case) to the partial from a controller.

IS there a best practice for this case, or I am just doing something so complicated I should do straight jQuery or something and leave rails out of it?

If I put the entire form (including the things each subclass has in common) in each subclasses form, that doesn't seem very dry. Not only that, I'm not sure that I would be able to then associate the StateDescription subclass back up to the parent class...

But, if I do it AJAX, I suppose I could not worry about nested forms and just have the parent be a hidden field or something, and have the StateDescriptions save on their own through AJAX?

Would this be the best solution (if it even works?) or is there some simple Rails way that I am missing?

4

2 回答 2

0

我对 STI 模型也有类似的问题,该模型由“has_many/belongs_to”关系中的另一个类拥有。为了动态地为这个其他类构建表单,我使用cocoongem 和simple_form.

Cocoon 为每个继承自 STI 基类的具体类添加了动态添加/删除字段的方法。

例如(Publication 是所有者类,Item 是基础 STI 模型,Post、Video 和 Image 都继承自它):

# _form.html.haml

= simple_form_for @publication, :html => { :multipart => true } do |f|

  = f.simple_fields_for :items do |item|
    = render 'item_fields', :f => item
    = link_to_add_association 'Add a Post', f, :items, :wrap_object => Proc.new { |item| item = Item.new }
    = link_to_add_association 'Add an Image', f, :items, :wrap_object => Proc.new { |item| item = Image.new }
    = link_to_add_association 'Add a Video', f, :items, :wrap_object => Proc.new { |item| item = Video.new }

    = f.button :submit, :disable_with => 'Please wait ...', :class => "btn btn-primary", :value => 'Save'

:wrap_objectproc 将呈现正确部分的具体类传递给它item_fields,例如image_fieldsorvideo_fields或其他。

我希望这有帮助。

我为这个问题写了一个更长的解释:http ://www.powpark.com/blog/programming/2014/05/07/rails_nested_forms_for_single_table_inheritance_associations

于 2014-05-07T21:36:45.663 回答
0

好吧,我仍然不知道这是最简单的还是 DRYist 的方法,但我最终将整个表单放在了部分表单中,然后就不再使用嵌套表单了。这与 AJAX 解决方案配合得很好。

每次都重复它们共有的表单元素让我感到难过,但对于 AJAX 功能来说这是值得的。

我会尝试做更多 DRY,我想到我可以尝试使子类部分不需要表单,但它仍然可以调用超类表单部分来插入每个子类共有的元素。

于 2013-09-07T14:10:48.033 回答