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.idundefined 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。