【问题标题】:Call create action through a form with a variable from another controller通过带有来自另一个控制器的变量的表单调用创建操作
【发布时间】:2014-08-03 19:44:03
【问题描述】:

我在 rails 4 应用中拥有的两个模型如下:

class Council < ActiveRecord::Base
    has_many :alternatives
    ...
end

class Alternative < ActiveRecord::Base
    belongs_to :council
    ...
end

我正在渲染一个替代表单,它允许我从委员会的展示视图中创建一个新的替代对象:

理事会/show.html.erb

<%= render 'alternatives/form' %>

alternatives/_form.html.erb

<%= form_for(@alternative) do |f| %>
  <div class="form-group">
      <div>
        <%= f.text_field :title, :placeholder => 'Provide your alternative', autofocus: true, class:"form-control" %>
      </div>
      <div>
        <%= f.text_area :more_info, :placeholder => 'Describe your alternative', autofocus: true, class:"form-control", rows: '4' %>
      </div>
  </div>
  <div>
      <%= f.submit 'Submit the alternative!', class:"btn btn-success"  %>
  </div>
<% end %>

此时,我想将 Alternative 对象与显示视图中的特定 Council 对象相关联,如下面的代码,但未定义变量 @council:

控制器/alternatives_controller.rb

class AlternativesController < ApplicationController
  before_action :set_alternative, only: [:show, :edit, :update, :destroy]

  def create
    @alternative = Alternative.new(alternative_params)
    @alternative.council = @council
  end

  private

    def set_alternative
      @alternative = Alternative.find(params[:id])
    end

    def alternative_params
      params.require(:alternative).permit(:title, :more_info)
    end
end

这将允许我显示与某个委员会对象相关的所有备选方案:

理事会/show.html.erb

...
<% @council.alternatives.each do |alternative| %>
    <%= alternative.title %>
    <%= alternative.more_info %>
<% end %>
...

我已经仔细查看了 Ruby on Rails 指南 (http://guides.rubyonrails.org/association_basics.html#belongs-to-association-reference),但显然我遗漏了一些东西。有任何想法吗?谢谢。

【问题讨论】:

    标签: ruby-on-rails forms ruby-on-rails-4 models model-associations


    【解决方案1】:

    为您提供多种选择:


    嵌套

    我尚未对此进行测试,但您可以在您的 form_for 助手中使用多个对象:

    #app/views/councils/show.html.erb
    <%= form_for [@council, @alternative] do |f| %>
     ...
    <% end %>
    

    这会将您的请求发送到council_alternatives_path(您可以更改它),并为您提供params[:council_id]params[:id]

    你可以像这样设置你的路线来让它工作:

    #config/routes.rb
    resources :councils do
       resources :alternatives, only: [:create]
    end
    

    我认为这会有点 hacky(因为它适用于具有 nested 属性的表单),但它仍然是实现您想要的可行方法


    嵌套属性

    另一种选择是在模型中使用accepts_nested_attributes_for 指令。我认为这对于您需要的东西来说太过分了,但可能会有所帮助:

    #app/models/council.rb
    Class Council < ActiveRecord::Base
       has_many :alternatives
       accepts_nested_attributes_for :alternatives
    end
    
    #app/models/alternative.rb
    Class Alternative < ActiveRecord::Base
       belongs_to :council
    end
    

    这将允许您使用@council 对象来保存您需要的任何新的Alternative 对象:

    #app/controllers/councils_controller.rb
    Class CouncilsController < ApplicationController
       def show
          @council = Council.find params[:id]
          @council.alternatives.build
       end
    
       def update
          @council = Council.find params[:id]
          @council.update(council_params)
       end
    
       private
    
       def council_params
          params.require(:council).permit(alterantives_attributes: [:alternatives, :attributes])
       end
    end
    

    这将允许您使用以下表单代码:

    #app/views/councils/show.html.erb
    <%= form_for @council do |f| %>
       <%= f.fields_for :alternatives do |a| %>
          <%= a.text_field :your_info %>
       <% end %>
       <% f.submit %>
    <% end %>
    

    【讨论】:

    • 谢谢!这解决了这个问题。我会选择你提供的第一个替代方案,它在场景中更有意义。
    【解决方案2】:

    你的routes.rb 是什么样的?在这种情况下,似乎最简单的方法是将您的 alternative 嵌套在您的 council 路由下,如下所示:

    资源:理事会做 资源:替代品 结束

    在这种情况下,在创建操作中的alternatives_controller.rb 中,您只需从参数中设置@council 对象。

    即。

      def create
        @council = Council.find(params[:council_id])
        @alternative = Alternative.new(alternative_params)
        @alternative.council = @council
        @alternative.save
      end
    

    【讨论】:

    • 谢谢!我将添加到您提供的内容中:&lt;%= form_for [@council, @alternative] do |f| %&gt; 正如@RichPeck 所说,这将完成解决方案。感谢您的回答!
    【解决方案3】:

    就我个人而言,我会将其嵌套在上述 derekyau 的路线中 (https://stackoverflow.com/a/25109545/3105349)

    但您也可以在表单中使用隐藏字段来传递理事会 ID,即

    <%= hidden_field :council_id, @council.id %>
    

    然后在控制器中你可以通过参数访问它

    @council = Council.find(params[:alternative][:council_id])
    

    或将其添加到您的替代参数中以自动分配它

    def alternative_params
      params.require(:alternative).permit(:title, :more_info, :council_id)
    end
    

    但同样,将其设为嵌套路由是更清洁且首选的解决方案。

    【讨论】:

    • 感谢您的回答,正如您所说,在这种情况下,嵌套路由是最好的方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-06
    • 1970-01-01
    • 2021-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多