通过带有来自另一个控制器的变量的表单调用create action

时间:2014-08-03 19:44:03

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

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

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

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

我正在渲染一个Alternative表单,允许我从Council的节目视图中创建一个新的Alternative对象:

议会/ show.html.erb

<%= render 'alternatives/form' %>

替代品/ _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对象与show视图中的特定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),但显然我遗漏了一些东西。有任何想法吗?谢谢。

3 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

就我个人而言,我会将它嵌入路线中的derekyau(https://stackoverflow.com/a/25109545/3105349

但你也可以使用表格中的隐藏字段来传递议会身份,即

<%= 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

但同样,使其成为嵌套路线是更清洁和首选的解决方案。

答案 2 :(得分:0)

有几种选择:


<强>嵌套

我没有对此进行测试,但您可以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 %>