collection_select不从其他模型插入值

时间:2018-02-10 14:15:19

标签: ruby-on-rails collection-select

我有两个模型,RoasterRoast

我想让用户从:roaster模型中选择新烘焙表单中Roaster的值。我正在使用collection_select在下拉列表中显示roaster列表,但它不会将值插入表中。从控制台,它实际上看起来像是试图通过roaster_id

"roast"=>{"roaster_id"=>"1", "name"=>"Rugby", "beans"=>"", "countries_attributes"=>{"0"=>{"country_name"=>"", "regions_attributes"=>{"0"=>{"region_name"=>""}}}, "1"=>{"country_name"=>"", "regions_attributes"=>{"0"=>{"region_name"=>""}}}, "2"=>{"country_name"=>"", "regions_attributes"=>{"0"=>{"region_name"=>""}}}}, "bestfor"=>"", "roast"=>"", "tastingnotes"=>""}, "commit"=>"Create Roast"}

我的选择:

<%= form.collection_select(:roaster_id, Roaster.all, :id, :roaster_name, :prompt => 'Select Roaster') %>

我试过

<%= form.collection_select(:roaster_name, Roaster.all, :id, :roaster_name, :prompt => 'Select Roaster') %>

但是这给出了未定义的方法错误。

我的roast_params

params.require(:roast).permit(:roaster, :roaster_id, :name, :bestfor, :beans, :roast, :tastingnotes, :notes, :slug, :avatar, countries_attributes: [:country_id, :country_name, regions_attributes: [:id, :region_name]])

添加:roaster_name也无法解决问题。

按要求提供完整表格:

<%= form_with(model: roast, local: true, multipart: true) do |form| %>
  <% if roast.errors.any? %>
    <div id="error_explanation">
      <div class="alert alert-danger" role="alert">
      <h2><%= pluralize(roast.errors.count, "error") %> prohibited this roast from being saved:</h2>

      <ul>
      <% roast.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  </div>
  <% end %>

<form>

<div class="row">
  <div class="col-6">
    <div class="field form-group">
      <%= form.label :roaster, class: 'control-label' %>
      <%= form.collection_select(:roaster_id, Roaster.all, :id, :roaster_name, :prompt => 'Select Roaster') %>
    </div>
  </div>
  <div class="col-6">
    <div class="form-group">
      <%= form.label :name, class: 'control-label' %>
      <%= form.text_field :name, class: "form-control" %>
    </div>
  </div>
</div>

  <div class="form-group">
    <%= form.label :beans, "Blend", class: 'control-label' %><br />
    <%= form.select :beans, [ 'Single Origin','Two Country Blend', 'Three Country Blend' ], :prompt => 'Select One', id: :roast_beans, class: "form-control" %>
  </div>

<div class="row">
  <%= form.fields_for :countries do |countries_form| %>
  <div class="col-6">

    <div class="form-group">

        <%= countries_form.label :country %>
        <%= countries_form.text_field :country_name, class: "form-control" %>
    </div>
  </div>
  <div class="col-6">
  <!-- note the appending of `countries_`  to form.fields to allow for deeper nested to work-->
        <%= countries_form.fields_for :regions do |regions_form| %>
          <%= regions_form.label :region %>
          <%= regions_form.text_field :region_name, class: "form-control" %>
        <% end %>
        <br />
    </div>
    <% end %>
</div>

  <div class="form-group">
    <%= form.label :bestfor, "Style", class: 'control-label' %><br />
    <%= form.select :bestfor, [ 'Espresso','Filter' ], :prompt => 'Select One', id: :roast_bestfor, class: "form-control" %>
  </div>

  <div class="form-group">
    <%= form.label :roast, "Strength", class: 'control-label' %><br />
    <%= form.select :roast, [ 'Light','Medium','Dark' ], :prompt => 'Select One', id: :roast_roast, class: "form-control" %>
  </div>

  <div class="form-group">
    <%= form.label :tastingnotes, "Tasting Notes (separate with commas, e.g chocolate, citrus)", class: 'control-label' %><br  />
    <%= form.text_area :tastingnotes, id: :roast_tastingnotes, class: "form-control" %>
  </div>
<br />

  <div class="form-group">
    <%= form.label :avatar, "Upload image...", class: 'control-label' %>
    <%= form.file_field :avatar %>
  </div>

  <div class="actions">
    <%= form.submit class: "btn btn-success" %> <%= link_to "Cancel", "/roasts", class: "btn btn-secondary"%>
  </div>
<% end %>

</form>

roast_controller.rb

class RoastsController < ApplicationController
  before_action :set_roast, only: [:show, :edit, :update, :destroy]
  before_action :authenticate_user!, only: [:create, :edit, :update, :destroy]
  before_action :set_search

  # GET /roasts
  # GET /roasts.json
  def index
      @q = Roast.ransack(params[:q])
      @roastsalpha = @q.result.order(:name)
      @roastcount = Roast.count(:country)
      @roasts = Roast.order(:name).count
      @countroastschart = Roast.order("roaster DESC").all

  end

  # GET /roasts/1
  # GET /roasts/1.json
  def show
    @roast = Roast.friendly.find(params[:id])
    @commentable = @roast
    @comments = @commentable.comments
    @comment = Comment.new
    @sameroaster = Roast.where(roaster: @roast.roaster)
    @samecountry = Roast.where(country: @roast.country)
    @roastcount = Roast.where(roaster: @roast.roaster)



  end

  # GET /roasts/new
  def new
    @roast = Roast.new
    3.times {@roast.countries.build.regions.build}
  end

  # GET /roasts/1/edit
  def edit
    3.times {@roast.countries.build.regions.build}
  end

  # POST /roasts
  # POST /roasts.json
  def create
    @roast = Roast.new(roast_params)

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

  # PATCH/PUT /roasts/1
  # PATCH/PUT /roasts/1.json
  def update
    respond_to do |format|
      if @roast.update(roast_params)
        format.html { redirect_to @roast, notice: 'Roast was successfully updated.' }
        format.json { render :show, status: :ok, location: @roast }
      else
        format.html { render :edit }
        format.json { render json: @roast.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /roasts/1
  # DELETE /roasts/1.json
  def destroy
    @roast.destroy
    respond_to do |format|
      format.html { redirect_to roasts_url, notice: 'Roast was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_roast
      @roast = Roast.friendly.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def roast_params
      params.require(:roast).permit(:roaster, :roaster_id, :name, :bestfor, :beans, :roast, :tastingnotes, :notes, :slug, :avatar, countries_attributes: [:country_id, :country_name, regions_attributes: [:id, :region_name]])
    end

end

1 个答案:

答案 0 :(得分:2)

我认为你做了很多错事。通过查看您的其他问题,我看到了您的模型。我提出了一些重要的事情:

class Roast < ApplicationRecord
  has_many :countries
  accepts_nested_attributes_for :countries
end

class Country < ApplicationRecord
  has_many :regions, inverse_of: :country
  accepts_nested_attributes_for :regions
  belongs_to :roast
end

class Region < ApplicationRecord
  belongs_to :country, inverse_of: :regions
end

在这些模型中,我没有看到Roaster。我假设Roast belongs_to :roaster

所以:你的 Roast有很多国家,每个国家都有很多地区。但是您将视图中的国家/地区名称和区域名称传递给创建控制器。您需要传递ID,以便保存对这些模型的引用。

params中有许多不必要的字段,还有一些缺少字段。这应该是这样的:

def roaster_params
  params.require(:roast).permit(:roaster_id, :name, :bestfor, :beans, :tastingnotes, :notes, :slug, :avatar, countries_attributes: [:id, regions_attributes: [:id]])
end

您不需要roast,roaster,country_name,region_name。您需要国家/地区的ID(而不是country_id),以及地区的ID(而不是region_id)

在您的表单中,您应该询问国家和地区ID:

<%= countries_form.collection_select(:id, Country.all, :id, :name, :prompt => 'Select Country') %>

<%= regions_form.collection_select(:id, Region.all, :id, :name, :prompt => 'Select Region') %>

事实上这更难,因为一个地区属于一个国家,但在这里你显示所有地区。您应该只显示所选国家/地区的区域(动态)。