将单个项目添加到rails has_many:through

时间:2017-06-26 23:42:53

标签: ruby-on-rails ruby has-many-through

我在客户和他们拥有的软件产品之间存在着很多关系。

# company.rb
class Company < ActiveRecord::Base
    has_many :company_sources
    has_many :sources, :through => :company_sources
end

# source.rb
class Source < ActiveRecord::Base
    has_many :company_sources
    has_many :companies, :through => :company_sources
end

# company_source.rb
class CompanySource < ActiveRecord::Base
    belongs_to :company
    belongs_to :source
end

控制器是默认的rails g scaffold <name>个文件

我需要在公司编辑页面上选择一个表格,以便在company_source表中添加单个来源。

我最接近的是使用选择表单助手,但是当我去添加新项目时,这将覆盖之前的添加。

我现在已经玩了好几个小时了,我似乎无法正确获取表格/路线/控制器。

这是我在撰写本文时正在玩的形式

<table>
  <% @company.sources.each do |source| %>
    <tr><%= source.name %></tr>
  <% end %>
  <tr>
      <%= form_for @company do |f| %>
        <td>
          <%= select("source", "id", Source.all.collect {|p| [ p.name, p.id ]}, { include_blank: true })%>
        </td>
        <td>
          <%= f.submit "Add Source" %>
        </td>
      <% end %>
  </tr>
</table>

完全控制者(再次,在撰写本文时)

&#13;
&#13;
class CompaniesController < ApplicationController
  before_action :set_company, only: [:show, :edit, :update, :destroy]

  # GET /companies
  # GET /companies.json
  def index
    @companies = Company.all
  end

  # GET /companies/1
  # GET /companies/1.json
  def show
  end

  # GET /companies/new
  def new
    @company = Company.new
  end

  # GET /companies/1/edit
  def edit
  end

  # POST /companies
  # POST /companies.json
  def create
    @company = Company.new(company_params)

    respond_to do |format|
      if @company.save
        format.html { redirect_to @company, notice: 'Company was successfully created.' }
        format.json { render :show, status: :created, location: @company }
      else
        format.html { render :new }
        format.json { render json: @company.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /companies/1
  # PATCH/PUT /companies/1.json
  def update
    respond_to do |format|
      if @company.update(company_params)
        format.html { redirect_to @company, notice: 'Company was successfully updated.' }
        format.json { render :show, status: :ok, location: @company }
      else
        format.html { render :edit }
        format.json { render json: @company.errors, status: :unprocessable_entity }
      end
      if (params[:source_id])
        @company.source << Source.find(params[:source_id])
      end
    end
  end

  # DELETE /companies/1
  # DELETE /companies/1.json
  def destroy
    @company.destroy
    respond_to do |format|
      format.html { redirect_to companies_url, notice: 'Company was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_company
      @company = Company.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def company_params
      params.require(:company).permit(:name, :description, :source_id)
    end
end
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:0)

update行动中,我建议不要@company.update,而是做:

company_source = CompanySource.create!(company: @company, source: Source.find(source_id)

(警告:代码中可能存在错误,您应该可以很容易地纠正错误)

因此,update操作看起来像:

def update
  respond_to do |format|
    company_source = CompanySource.new(company: @company, source_id: params[:source_id])

    if company_source.save
      format.html { redirect_to @company, notice: 'Company was successfully updated.' }
      format.json { render :show, status: :ok, location: @company }
    else
      format.html { render :edit }
      format.json { render json: company_source.errors, status: :unprocessable_entity }
    end
  end
end

虽然这会将视角转移到CompanySource的视角,尽管它位于CompaniesController内,但您真正想要做的是创建一个新的CompanySource。我认为这是看待它的最直接的方式。

这将确保正确更新Compnay - Source关系。