我尝试创建一个表单,根据用户的选择生成嵌套表单的副本。我有3个模型:可视化,其中有很多行,其中有很多窗格。
我希望能够允许用户单击一个小的下拉菜单,该菜单将生成一行,然后选择1,2或3个窗格。根据他们的选择,这将从渲染中生成他们选择的形式。
首先。我知道我需要稍微改变一下我的控制器,但我不知道如何用嵌套的形式做到这一点,因为在我见过的每个例子中,你需要预先确定你有多少次会"建立"嵌套的模型表单(不确定这是否是正确的术语)。我不确定如何使这部分动态化。
这就是我的意思:
//visualization_controller.rb
def new
@visualization = Visualization.new
rows = @visualization.rows.build
panes = rows.panes.build
end

这是一个渲染示例,如果usr想要生成一个只有1个窗格的行,则会调用该渲染:
<div class="medium-12 columns one_box_wrapper first" style="display:none">
<%= f.fields_for :rows, Row.new do |r| %>
<%= r.label :rowtitle %>
<%= r.text_field :rowtitle %>
<div class="nested" style="display:inline-block">
<%= r.fields_for :panes, Pane.new do |p| %>
<%= p.label :text %>
<%= p.text_field :text %>
<div class="mehv">
<img id="img_prev" width=300 height=300 src="#" alt="your image" class="img-thumbnail hidden"/> <br/>
<span class="meh">
Upload Pane Image<%= p.file_field :pane_photo, id: "pane_photo" %>
</span>
<%= p.hidden_field :pane_photo_cache %>
</div>
<% end %>
</ul>
</div>
<% end %>
</div>
&#13;
这可能在铁轨中吗?我觉得javascript会起作用,但我不认为你可以通过JS渲染服务器端代码。
我对此感到有些不满,任何帮助都将不胜感激!
修改
我最终使用了cocoon gem,因为它似乎让我的生活变得更轻松了。但我无法在索引页面上获得所有显示的可视化效果!我不知道问题是什么..封面标题和图片显示但没有别的!
//schema.rb
create_table "panes", force: :cascade do |t|
t.integer "row_id", null: false
t.text "text"
t.string "pane_photo"
end
create_table "rows", force: :cascade do |t|
t.integer "visualization_id", null: false
t.string "rowtitle"
end
create_table "visualizations", force: :cascade do |t|
t.string "title", null: false
t.string "cover_image"
end
&#13;
//controller.rb
class VisualizationsController < ApplicationController
before_action :authenticate_user!, except: [:index, :show]
before_action :authorize_user, except: [:index, :show]
helper_method :resource
def index
@visualizations = Visualization.all
@visualization = Visualization.new
end
def new
@visualization = Visualization.new
rows = @visualization.rows.build
panes = rows.panes.build
end
def create
@visualization = Visualization.new(visualization_params)
if @visualization.save
redirect_to edit_visualization_path(@visualization)
else
render :new
end
end
def edit
@visualizations = Visualization.all
@visualization = Visualization.find(params[:id])
end
protected
def visualization_params
params.require(:visualization).permit(:title, :cover_image, rows_attributes: [:visualization_id, :rowtitle, panes_attributes:[:text, :pane_photo]])
end
&#13;
//index.html
<div class="visual_wrap text-center">
<ul class="no-bullet text-center">
<% @visualizations.each do |visualization| %>
<li class="text-center">
<div class="row visualization text-center">
<%= image_tag visualization.cover_image.to_s, id: "visualization_image", class: "output_image" %>
<p class="visualization_title"><%= visualization.title %></p>
<a href="#" id="visualization_link"><p>+</p></a>
</div>
<div class="placeholder">
<% visualization.rows.each do |row| %>
<%= row.rowtitle %>
<% row.panes.each do |p| %>
<%= p.text %>
<%= image_tag p.pane_photo.to_s, id: "pane_image", class: "output_image" %>
<% end %>
<% end %>
</div>
</li>
<% end %>
</ul>
</div>
&#13;
//new.html.erb
<% if user_signed_in? %>
<% if current_user.admin? %>
<div class="try">
<div class="breadcrumb-wrapper">
<ul class="breadcrumbs">
<%= form_for @visualization, :html => {:multipart => true} do |f| %>
<li><a href="#" class="preview button secondary">Preview</a></li>
<li><div class="separating-bar">|</div>
<li><input type="submit" name="commit" value="Save" class="save button secondary"></li>
</ul>
</div>
<div class="cover_image text-center">
<div class="row pre_img_prev">
<div class="gray_bar"></div>
<div class="img_prev">
<img id="img_preview" src="#" alt="your image" class="img-thumbnail hidden text-center"/>
<input type="text" name="visualization[title]" id="visualization[title]" class="inputtext" />
<label for="visualization[title]" id="text_preview">+ Add Title</label>
<div class="trash-can_title">
<a href="#" id="trash-can_title"><i class="fa fa-trash fa-3x" aria-hidden="true"></i></a>
</div>
</div>
<input type="file" name="visualization[cover_image]" id="visualization_cover_image" class="inputfile" />
<label for="visualization_cover_image">+ Add Cover Image</label>
<%= f.hidden_field :cover_image_cache %>
<div class="trash-can_cover">
<a href="#" id="trash-can_cover"><i class="fa fa-trash fa-3x" aria-hidden="true"></i></a>
</div>
</div>
</div>
<div class="row linkstest">
<div class="rows">
<%= f.fields_for :rows, Row.new do |task| %>
<%= render 'row_fields', f: task %>
<% end %>
<div class="links">
<%= link_to_add_association "Add Row", f, :rows %>
</div>
</div>
<% end %>
<% end %>
<% end %>
</div>
</div>
&#13;
答案 0 :(得分:0)
你不需要真正需要JS,除了让它更多&#34; snappy&#34;。我认为你要找的是嵌套表格。
看看RaisCast它有点过时,但它是一个很好的基础。
您可能需要查看Cocoon gem以帮助您动态创建新字段。
Rails nested_form inside nested_form
<强>更新强>
如果您根本不想使用Javascript,则需要向控制器发出额外请求,告诉它为您初始化(构建)行和窗格,以便它呈现空的字段。视图。 例如:
def new
@visualization = Visualization.new
num_rows = params[:num_rows]
num_rows.each { @visualization.rows.build }
end
您还需要在每行中包含窗格数,因此参数必须位于行属性中,例如params[:visualization][:rows][0][:num_panes]
,并使用该参数初始化行中的窗格。将该逻辑放在工厂服务中可能是最好的。
但是,如果使用JS创建空字段,则可以避免发出额外请求和所有逻辑。这是因为如果为其提供正确的属性,Rails将自动初始化(构建)行和窗格,例如:
{
visualization: {
rows_attributes: {
# These are the attributes from an existing record
0: {
id: 39,
panes_attributes: {
0: {
id: 992
}
}
},
# This is a new set of attributes for a new record
# passed by the fields generated by cocoon where xxx
# and yyy are random numbers
xxxx: {
panes_attributes: {
yyyy: {
}
}
}
}
}
}
然后您需要在控制器中执行的操作是:
def new
# visualization_params are the permitted attributes
@visualization = Visualization.new(visualization_params)
end