Rails:在 bootstrap 模态中为 belongs_to 关联创建 form_for
Rails: creating a form_for for a belongs_to association within a bootstrap modal
在我的 rails 应用程序中,我在 Costs/Cost_Dependencies
之间有一个 has_many/belongs_to 关联
用户可以创建新的成本,然后通过索引操作查看,没什么特别的。但我正在尝试添加在成本创建后为成本创建 Cost_dependency 的功能。我已经准备好了所有的部分,我只需要在 bootstrap 模态中执行(为了提高效率)。
在我网站的索引视图中,用户会看到所有费用的 table:
在 dependencies 列下方,我希望用户能够单击 + 按钮和一个模式来弹出表单。
以下是我目前已有的内容:
我的路线给我这个:
cost_cost_dependencies GET /costs/:cost_id/cost_dependencies(.:format) cost_dependencies#index
POST /costs/:cost_id/cost_dependencies(.:format) cost_dependencies#create
new_cost_cost_dependency GET /costs/:cost_id/cost_dependencies/new(.:format) cost_dependencies#new
edit_cost_cost_dependency GET /costs/:cost_id/cost_dependencies/:id/edit(.:format) cost_dependencies#edit
cost_cost_dependency GET /costs/:cost_id/cost_dependencies/:id(.:format) cost_dependencies#show
PATCH /costs/:cost_id/cost_dependencies/:id(.:format) cost_dependencies#update
PUT /costs/:cost_id/cost_dependencies/:id(.:format) cost_dependencies#update
DELETE /costs/:cost_id/cost_dependencies/:id(.:format) cost_dependencies#destroy
所以我显然有能力通过成本来创造这个东西。 (如果可以的话,我尽量避免为 cost_dependencies 使用单独的控制器,但如果不行,请告诉我。)
在成本视图的索引中,我有这些部分:
<div class="btn-group" style="margin:0; height:100%; float: center !important">
<%= link_to '<i class="glyphicon glyphicon-eye-open"></i>'.html_safe, "/costs/#{cost.id}/cost_dependencies", class: 'btn btn-warning' %>
<%= link_to '<i class="glyphicon glyphicon-plus"></i>'.html_safe, "/costs/#{cost.id}/cost_dependencies/new", {:remote => true, 'data-toggle' => "modal", 'data-target' => '#modal-window', :class => 'btn btn-success'} %>
</div>
和
<div id="modal-window" class="modal fade" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<%= render 'costs/new_cost_dependency' %>
</div>
</div>
</div>
我确实也计划实现一个模式来查看依赖关系,但我认为回答这个问题会帮助我实现这一点。
然后对于部分内的模态主体:
<div class="modal-body">
<%= form_for @cost_dependency, :html => {:class => "form-group"} do |f| %>
Blah Blah form stuff looking like <%= f.label ... %> and <%= f.text_field ... %>
<% end %>
</div>
我坚持的部分是如何通过控制器中的 database_association 在表单中实例化 @cost_dependency 变量,因为我一直在接收
First argument in form cannot contain nil or be empty
尝试重新加载页面时出错。
任何有助于实现这一目标的帮助都会非常有帮助。
非常感谢
编辑: 这是我的成本控制器:
def index
@costs = Cost.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: @costs }
end
end
def show
end
def new
@cost = Cost.new
@new = true
respond_to do |format|
format.html # new.html.erb
format.json { render json: @cost }
end
end
def edit
@edit = true
@cost = Cost.find(params[:id])
end
def create
@cost = Cost.new(cost_params)
if Cost.exists?(:category => @cost.category, :option => @cost.option)
redirect_to action: 'update', id: Cost.where(:category => @cost.category, :option => @cost.option).first.id
else
respond_to do |format|
if @cost.save
format.html { redirect_to action: 'index', status: 303, notice: [true, 'Cost was successfully created.'] }
format.json { render json: @cost, status: :created, location: @cost }
else
format.html { render action: "new" }
format.json { render json: @cost.errors, status: :unprocessable_entity }
end
end
end
end
def update
@cost = Cost.find(params[:id])
respond_to do |format|
if @cost.update_attributes(cost_params)
format.html { redirect_to action: 'index', status: 303, notice: [true, 'Cost was successfully updated.'] }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: @cost.errors, status: :unprocessable_entity }
end
end
end
所以我意识到我的 @cost_dependency
变量不在这里。如果我把它放在新的位置,它就不会被调用,因为我们目前正在进行 index
操作。因此,在这方面提供帮助也会有所帮助。
自从我发布这个问题以来,我确实制作了一个具有类似功能的 CostDependency
控制器。
Edit2: 所以我一直在尝试新事物,我已经走得更远了,但又卡住了。
我有一个新的索引页:
<tbody>
<% @costs.each do |cost| %>
<tr>
<td style="vertical-align:middle !important"><%= cost.category %></td>
<td style="vertical-align:middle !important"><%= cost.option %></td>
<td style="vertical-align:middle !important"><%= '$'+cost.per_job.to_s %></td>
<td style="vertical-align:middle !important"><%= '$'+cost.per_page.to_s %></td>
<td style="vertical-align:middle !important">
<div class="btn-group" style="margin:0; height:100%; float: center !important">
<%if Cost.where(:id => cost.id)[0].cost_dependencies.empty? %>
<span class="btn btn-danger" data-toggle="popover" data-trigger="hover" data-placement="top" data-html="true" data-content="<h5 style='color: black;'>No Dependencies for this Cost</h5>"><i class="glyphicon glyphicon-eye-close"></i></span>
<% else %>
<%= link_to '<i class="glyphicon glyphicon-eye-open"></i>'.html_safe, "", {:remote => true, 'data-toggle' => "modal", 'data-target' => '#modal-window', :class => 'btn btn-warning', :cost => cost.id} %>
<% end %>
<%= link_to '<i class="glyphicon glyphicon-plus"></i>'.html_safe, "", {:remote => true, 'data-toggle' => "modal", 'data-target' => '#modal-new-dependency', :cost => cost.id, :class => 'btn btn-success'} %>
</div>
</td>
<td style="vertical-align:middle !important">
<div class="btn-group" style="margin:0; height:100%; float: center !important">
<%= link_to '<i class="glyphicon glyphicon-pencil"></i>'.html_safe, "/costs/#{cost.id}/edit", class: 'btn btn-info'%>
<%= link_to '<i class="glyphicon glyphicon-trash"></i>'.html_safe, cost, method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger' %>
</div>
</td>
</tr>
<div id="modal-window" class="modal fade" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<%= render 'costs/dependency_index', :cost => Cost.where(:id => cost.id)[0] %>
</div>
</div>
</div>
<div id="modal-new-dependency" class="modal fade" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<%= render 'costs/new_cost_dependency', :cost => Cost.where(:id => cost.id)[0] %>
</div>
</div>
</div>
<% end %>
</tbody>
这不会引发错误,但是当我单击 +
时,我只收到第一个成本,在这种情况下 Size - 8.5" x 11"
我的日志爆炸了,好像它正在尝试到 select 所有这些,这有点有意义,因为它在 .each
循环中。
但是如果我把它拉出来,我会得到 cost.id
的 undefined variable
错误,因为它不存在于范围
之外
好吧,我想通了这只野兽。在我回答时坚持我。
ajax 是你最好的朋友。
因此:首先,将 new
(加号)方法的 link_to
更改为按钮:
<button class="btn btn-success" data-toggle="modal" data-target="#new-dependency-modal-window" id="newdependency">
<%= hidden_field_tag "cost_id", cost.id %>
<span class="glyphicon glyphicon-plus"></span>
</button>
像这样。请注意,/cost/:id/cost_dependencies/new
根本没有 link,稍后将发挥作用。
在最后的 div
下方(在您的文件的末尾),添加此代码以确保存在模态
<div id="new-dependency-modal-window" class="modal fade" role="dialog" aria-labelledby="myNewDependencyModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document" id="new_cost_dependency_modal" style="width: 85%">
</div>
</div>
接下来,为 Cost Dependencies 创建一个控制器,并添加常规方法:
class CostDependenciesController < ApplicationController
def new
@cost = Cost.find(params[:cost_id])
@cost_dependency = CostDependency.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: @cost_dependency }
end
end
def edit
@edit = true
@cost = Cost.find(params[:cost_id])
@cost_dependency = @cost.cost_dependencies.find(params[:id])
end
def index
end
def create
@cost = Cost.find(params[:cost_id])
@cost_dependency = @cost.cost_dependencies.new(cost_dependencies_params)
respond_to do |format|
if @cost_dependency.save
format.html { redirect_to controller: 'costs', action: 'index', status: 303, notice: [true, 'Cost Dependency was successfully created.'] }
format.json { render json: @cost_dependency, status: :created, location: @cost }
else
format.html { render action: "new" }
format.json { render json: @cost_dependency.errors, status: :unprocessable_entity }
end
end
end
def update
@cost = Cost.find(params[:cost_id])
@cost_dependency = @cost.cost_dependencies.find(params[:id])
respond_to do |format|
if @cost_dependency.update_attributes(cost_dependencies_params)
format.html { redirect_to controller: 'costs', action: 'index', status: 303, notice: [true, 'Cost was successfully updated.'] }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: @cost.errors, status: :unprocessable_entity }
end
end
end
def destroy
@cost = Cost.find(params[:cost_id])
@cost_dependency = @cost.cost_dependencies.find(params[:id])
@cost_dependency.destroy
respond_to do |format|
format.html { redirect_to controller: 'costs', action: 'index', status: 303, alert: [true, 'Cost Dependency has been deleted.'] }
format.json { head :no_content }
end
end
private
def cost_dependencies_params
params.require(:cost_dependency).permit(:cost_id, :dependency_category, :dependency_option, :per_job, :per_page)
end
end
注意每个方法中如何有 @cost = Cost.find(params[:cost_id])
这将为您获取正确的 Cost
,您可以为其调用 @cost.cost_dependencies.new
方法。这就是按钮标签内的 hidden_field 标签的原因,使参数可以被 jQuery.
找到
从这里开始,目标是使用 ajax 调用从 jQuery 调用新方法,然后我们将抓取内容并将其推入模式。
$(document).on "turbolinks:load", ->
$('button[id="newdependency"]').click ->
cost_id = $(this).find('#cost_id').val()
$.ajax({
url: 'costs/'+cost_id+'/cost_dependencies/new',
type: 'GET',
data: {cost_id: cost_id},
dataType: 'html',
success: (data) ->
dependencyform = $($.parseHTML(data)).find("#new_dependency_modal")
$('#new_cost_dependency_modal').html(dependencyform)
})
所以我们在单击带有 newdependency
id 的按钮后执行,我们从页面加载返回 html(这将是整个页面、导航栏和所有页面。但我们标记我们想要的内容(参见 new_dependency_modal
),以便我们可以 find()
它。我们将 html 设置在我们当前仍在访问的页面上的模态 div
中.
注意:这里的this
很重要,否则会抢到页面上找到的第一个cost_id,这样就不好了,所以我们将范围本地化。
为了清楚起见,这里是我的 new.html.erb
被调用的页面。
<div class="modal-content" id="new_dependency_modal">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h2 style="color: #49afcd" class="center-block westmontTextMuseo3">New Cost Dependency for - <%= @cost.category+" - "+@cost.option %></h2>
</div>
<div class=modal-body>
<%= render 'form' %>
</div>
</div>
其中表单只是创建新表单的表单 cost_dependency。
在我的 rails 应用程序中,我在 Costs/Cost_Dependencies
之间有一个 has_many/belongs_to 关联用户可以创建新的成本,然后通过索引操作查看,没什么特别的。但我正在尝试添加在成本创建后为成本创建 Cost_dependency 的功能。我已经准备好了所有的部分,我只需要在 bootstrap 模态中执行(为了提高效率)。
在我网站的索引视图中,用户会看到所有费用的 table:
在 dependencies 列下方,我希望用户能够单击 + 按钮和一个模式来弹出表单。
以下是我目前已有的内容: 我的路线给我这个:
cost_cost_dependencies GET /costs/:cost_id/cost_dependencies(.:format) cost_dependencies#index
POST /costs/:cost_id/cost_dependencies(.:format) cost_dependencies#create
new_cost_cost_dependency GET /costs/:cost_id/cost_dependencies/new(.:format) cost_dependencies#new
edit_cost_cost_dependency GET /costs/:cost_id/cost_dependencies/:id/edit(.:format) cost_dependencies#edit
cost_cost_dependency GET /costs/:cost_id/cost_dependencies/:id(.:format) cost_dependencies#show
PATCH /costs/:cost_id/cost_dependencies/:id(.:format) cost_dependencies#update
PUT /costs/:cost_id/cost_dependencies/:id(.:format) cost_dependencies#update
DELETE /costs/:cost_id/cost_dependencies/:id(.:format) cost_dependencies#destroy
所以我显然有能力通过成本来创造这个东西。 (如果可以的话,我尽量避免为 cost_dependencies 使用单独的控制器,但如果不行,请告诉我。)
在成本视图的索引中,我有这些部分:
<div class="btn-group" style="margin:0; height:100%; float: center !important">
<%= link_to '<i class="glyphicon glyphicon-eye-open"></i>'.html_safe, "/costs/#{cost.id}/cost_dependencies", class: 'btn btn-warning' %>
<%= link_to '<i class="glyphicon glyphicon-plus"></i>'.html_safe, "/costs/#{cost.id}/cost_dependencies/new", {:remote => true, 'data-toggle' => "modal", 'data-target' => '#modal-window', :class => 'btn btn-success'} %>
</div>
和
<div id="modal-window" class="modal fade" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<%= render 'costs/new_cost_dependency' %>
</div>
</div>
</div>
我确实也计划实现一个模式来查看依赖关系,但我认为回答这个问题会帮助我实现这一点。
然后对于部分内的模态主体:
<div class="modal-body">
<%= form_for @cost_dependency, :html => {:class => "form-group"} do |f| %>
Blah Blah form stuff looking like <%= f.label ... %> and <%= f.text_field ... %>
<% end %>
</div>
我坚持的部分是如何通过控制器中的 database_association 在表单中实例化 @cost_dependency 变量,因为我一直在接收
First argument in form cannot contain nil or be empty
尝试重新加载页面时出错。
任何有助于实现这一目标的帮助都会非常有帮助。 非常感谢
编辑: 这是我的成本控制器:
def index
@costs = Cost.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: @costs }
end
end
def show
end
def new
@cost = Cost.new
@new = true
respond_to do |format|
format.html # new.html.erb
format.json { render json: @cost }
end
end
def edit
@edit = true
@cost = Cost.find(params[:id])
end
def create
@cost = Cost.new(cost_params)
if Cost.exists?(:category => @cost.category, :option => @cost.option)
redirect_to action: 'update', id: Cost.where(:category => @cost.category, :option => @cost.option).first.id
else
respond_to do |format|
if @cost.save
format.html { redirect_to action: 'index', status: 303, notice: [true, 'Cost was successfully created.'] }
format.json { render json: @cost, status: :created, location: @cost }
else
format.html { render action: "new" }
format.json { render json: @cost.errors, status: :unprocessable_entity }
end
end
end
end
def update
@cost = Cost.find(params[:id])
respond_to do |format|
if @cost.update_attributes(cost_params)
format.html { redirect_to action: 'index', status: 303, notice: [true, 'Cost was successfully updated.'] }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: @cost.errors, status: :unprocessable_entity }
end
end
end
所以我意识到我的 @cost_dependency
变量不在这里。如果我把它放在新的位置,它就不会被调用,因为我们目前正在进行 index
操作。因此,在这方面提供帮助也会有所帮助。
自从我发布这个问题以来,我确实制作了一个具有类似功能的 CostDependency
控制器。
Edit2: 所以我一直在尝试新事物,我已经走得更远了,但又卡住了。
我有一个新的索引页:
<tbody>
<% @costs.each do |cost| %>
<tr>
<td style="vertical-align:middle !important"><%= cost.category %></td>
<td style="vertical-align:middle !important"><%= cost.option %></td>
<td style="vertical-align:middle !important"><%= '$'+cost.per_job.to_s %></td>
<td style="vertical-align:middle !important"><%= '$'+cost.per_page.to_s %></td>
<td style="vertical-align:middle !important">
<div class="btn-group" style="margin:0; height:100%; float: center !important">
<%if Cost.where(:id => cost.id)[0].cost_dependencies.empty? %>
<span class="btn btn-danger" data-toggle="popover" data-trigger="hover" data-placement="top" data-html="true" data-content="<h5 style='color: black;'>No Dependencies for this Cost</h5>"><i class="glyphicon glyphicon-eye-close"></i></span>
<% else %>
<%= link_to '<i class="glyphicon glyphicon-eye-open"></i>'.html_safe, "", {:remote => true, 'data-toggle' => "modal", 'data-target' => '#modal-window', :class => 'btn btn-warning', :cost => cost.id} %>
<% end %>
<%= link_to '<i class="glyphicon glyphicon-plus"></i>'.html_safe, "", {:remote => true, 'data-toggle' => "modal", 'data-target' => '#modal-new-dependency', :cost => cost.id, :class => 'btn btn-success'} %>
</div>
</td>
<td style="vertical-align:middle !important">
<div class="btn-group" style="margin:0; height:100%; float: center !important">
<%= link_to '<i class="glyphicon glyphicon-pencil"></i>'.html_safe, "/costs/#{cost.id}/edit", class: 'btn btn-info'%>
<%= link_to '<i class="glyphicon glyphicon-trash"></i>'.html_safe, cost, method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger' %>
</div>
</td>
</tr>
<div id="modal-window" class="modal fade" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<%= render 'costs/dependency_index', :cost => Cost.where(:id => cost.id)[0] %>
</div>
</div>
</div>
<div id="modal-new-dependency" class="modal fade" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<%= render 'costs/new_cost_dependency', :cost => Cost.where(:id => cost.id)[0] %>
</div>
</div>
</div>
<% end %>
</tbody>
这不会引发错误,但是当我单击 +
时,我只收到第一个成本,在这种情况下 Size - 8.5" x 11"
我的日志爆炸了,好像它正在尝试到 select 所有这些,这有点有意义,因为它在 .each
循环中。
但是如果我把它拉出来,我会得到 cost.id
的 undefined variable
错误,因为它不存在于范围
好吧,我想通了这只野兽。在我回答时坚持我。
ajax 是你最好的朋友。
因此:首先,将 new
(加号)方法的 link_to
更改为按钮:
<button class="btn btn-success" data-toggle="modal" data-target="#new-dependency-modal-window" id="newdependency">
<%= hidden_field_tag "cost_id", cost.id %>
<span class="glyphicon glyphicon-plus"></span>
</button>
像这样。请注意,/cost/:id/cost_dependencies/new
根本没有 link,稍后将发挥作用。
在最后的 div
下方(在您的文件的末尾),添加此代码以确保存在模态
<div id="new-dependency-modal-window" class="modal fade" role="dialog" aria-labelledby="myNewDependencyModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document" id="new_cost_dependency_modal" style="width: 85%">
</div>
</div>
接下来,为 Cost Dependencies 创建一个控制器,并添加常规方法:
class CostDependenciesController < ApplicationController
def new
@cost = Cost.find(params[:cost_id])
@cost_dependency = CostDependency.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: @cost_dependency }
end
end
def edit
@edit = true
@cost = Cost.find(params[:cost_id])
@cost_dependency = @cost.cost_dependencies.find(params[:id])
end
def index
end
def create
@cost = Cost.find(params[:cost_id])
@cost_dependency = @cost.cost_dependencies.new(cost_dependencies_params)
respond_to do |format|
if @cost_dependency.save
format.html { redirect_to controller: 'costs', action: 'index', status: 303, notice: [true, 'Cost Dependency was successfully created.'] }
format.json { render json: @cost_dependency, status: :created, location: @cost }
else
format.html { render action: "new" }
format.json { render json: @cost_dependency.errors, status: :unprocessable_entity }
end
end
end
def update
@cost = Cost.find(params[:cost_id])
@cost_dependency = @cost.cost_dependencies.find(params[:id])
respond_to do |format|
if @cost_dependency.update_attributes(cost_dependencies_params)
format.html { redirect_to controller: 'costs', action: 'index', status: 303, notice: [true, 'Cost was successfully updated.'] }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: @cost.errors, status: :unprocessable_entity }
end
end
end
def destroy
@cost = Cost.find(params[:cost_id])
@cost_dependency = @cost.cost_dependencies.find(params[:id])
@cost_dependency.destroy
respond_to do |format|
format.html { redirect_to controller: 'costs', action: 'index', status: 303, alert: [true, 'Cost Dependency has been deleted.'] }
format.json { head :no_content }
end
end
private
def cost_dependencies_params
params.require(:cost_dependency).permit(:cost_id, :dependency_category, :dependency_option, :per_job, :per_page)
end
end
注意每个方法中如何有 @cost = Cost.find(params[:cost_id])
这将为您获取正确的 Cost
,您可以为其调用 @cost.cost_dependencies.new
方法。这就是按钮标签内的 hidden_field 标签的原因,使参数可以被 jQuery.
从这里开始,目标是使用 ajax 调用从 jQuery 调用新方法,然后我们将抓取内容并将其推入模式。
$(document).on "turbolinks:load", ->
$('button[id="newdependency"]').click ->
cost_id = $(this).find('#cost_id').val()
$.ajax({
url: 'costs/'+cost_id+'/cost_dependencies/new',
type: 'GET',
data: {cost_id: cost_id},
dataType: 'html',
success: (data) ->
dependencyform = $($.parseHTML(data)).find("#new_dependency_modal")
$('#new_cost_dependency_modal').html(dependencyform)
})
所以我们在单击带有 newdependency
id 的按钮后执行,我们从页面加载返回 html(这将是整个页面、导航栏和所有页面。但我们标记我们想要的内容(参见 new_dependency_modal
),以便我们可以 find()
它。我们将 html 设置在我们当前仍在访问的页面上的模态 div
中.
注意:这里的this
很重要,否则会抢到页面上找到的第一个cost_id,这样就不好了,所以我们将范围本地化。
为了清楚起见,这里是我的 new.html.erb
被调用的页面。
<div class="modal-content" id="new_dependency_modal">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h2 style="color: #49afcd" class="center-block westmontTextMuseo3">New Cost Dependency for - <%= @cost.category+" - "+@cost.option %></h2>
</div>
<div class=modal-body>
<%= render 'form' %>
</div>
</div>
其中表单只是创建新表单的表单 cost_dependency。