Ruby:在使用嵌套表单时,如何在控制器中指定值?

时间:2015-10-20 08:07:33

标签: ruby-on-rails ruby forms ruby-on-rails-4 nested-forms

我有3个模型:雇主,合作伙伴和合作。

作为雇主,我想在我的合作伙伴模型和我的协作模型中添加记录,以便能够指示合作伙伴和雇主之间的协作。因此,我的数据库/表格中有以下列。

模型

class Employer < ActiveRecord::Base
  has_many :collaborations
  has_many :partners, :through => :collaborations
end

class Partner < ActiveRecord::Base  
  has_many :collaborations
  has_many :employers, :through => :collaborations
  accepts_nested_attributes_for :collaborations
end

class Collaboration < ActiveRecord::Base
  belongs_to :employer
  belongs_to :partner
end

表格

Collaborations
  employer_id:integer
  partner_id:integer
  tarive:string

Partners
  added_by:integer
  name:string

因为我希望能够在1个表单中添加合作伙伴/协作,所以我使用嵌套表单。所以我可以一次性添加合作伙伴(名称等)和协作(tarive等)。

我的(simple_form)表单看起来像这样(我有named_space资源)。 为了减少混乱,我删除了尽可能多的HTML mark_up,这不是问题。

表格

/视图/雇主/伙伴/ _form

= simple_form_for [:employer, @partner], html: { multipart: true } do |f| 
  Partner
  = f.input :name, input_html: { class: 'form-control' }

  = f.simple_fields_for :collaborations do |ff|
    Tarive
    = ff.input :tarive, input_html: { class: 'form-control' }

= f.button :submit, "Save"

我的控制器看起来像

class Employer::PartnersController < ActionController::Base
  def new
    @partner = Partner.new
    @partner.collaborations.build
  end

  def create
    @partner = Partner.new(partner_params)
    @partner.collaborations.build
    @partner.added_by = current_employer.id
    @partner.collaborations.employer_id = current_employer.employer_id
    @partner.collaborations.partner_id = @partner.id
    @partner.collaborations.added_by = current_employer.id

    if @partner.save
      redirect_to employer_partner_path(@partner), notice: "Succes!"
    else
      render 'new'
    end
  end

  def partner_params
    params.require(:partner).permit(:id, :name, collaborations_attributes: [:id, :employer_id, :partner_id, :tarive])
  end
end

问题

我遇到的问题是这个问题。属性很好地分配并添加到模型中。但我想添加一个employer_id,我在current_employer.employer.id(设计)中添加了@partner.added_by = current_employer.id。我不想使用隐藏的表单,只是为了避免这个问题。

我指定了父母&#39;模型总是像@partner.collaborations.employer_id = current_employer.employer_id 一样,效果很好。

当我使用时:

@partner.collaborations.employer_id

我收到错误,说current_employer.employer_id为空。

问题

如何在我的控制器#create中为nested_form(Collaboration)分配变量? 或者更具体地说:我如何将@partner.collaborations.employer_id分配给docx

1 个答案:

答案 0 :(得分:2)

有几种方法:

  
      
  1. 合并参数
  2.   
  3. 处理对象,而不是外键
  4.   

就个人而言,我觉得你的create方法看起来效率很低。实际上,您应该知道关联逻辑的fat model skinny controller - 大多数应保留在模型中。

可以使用以下方法进行改进:

#app/controllers/employers/partners_controller.rb
class Employers::PartnersController < ApplicationController

   def new
      @partner = current_employer.partners.new #-> this *should* build the associated collaborations object 
   end

   def create
      @partner = current_employer.partners.new partner_params       
      @partner.save ? redirect_to(employer_partner_path(@partner), notice: "Succes!") : render('new')
   end

   private

   def partner_params
       params.require(:partner).permit(:id, :name, collaborations_attributes: [:tarive]) #when dealing with objects, foreign keys are set automatically
   end
end

这将允许您使用:

#app/views/employers/partners/new.html.erb
= simple_form_for @partner do |f| #-> @partner is built off the current_employer object
  = f.input :name
  = f.simple_fields_for :collaborations do |ff|
    = ff.input :tarive
= f.submit

......和模特:

#app/models/partner.rb
class Partner < ActiveRecord::Base
    belongs_to :employer, foreign_key: :added_by

    has_many :collaborations
    has_many :employers, through: :collaborations

    accepts_nested_attributes_for :collaborations
end

#app/models/collaboration.rb
class Collaboration < ActiveRecord::Base
    belongs_to :employer
    belongs_to :partner

    belongs_to :creator, foreign_key: :added_by

    before_create :set_creator

    private

    def set_creator
         self.creator = self.employer_id #-> will probably need to change
    end
end

#app/models/employer.rb
class Employer < ActiveRecord::Base
    has_many :collaborations
    has_many :employers, through: :collaborations
end

这可能使您能够设置tarive,但是如果您减少模型中的手动声明,我们应该能够看到对它进行排序。

您需要做的主要是减少控制器中的代码。你是非常具体的,因此,你遇到的问题就像你提到的那样。