【问题标题】:collection_select not inserting value from other modelcollection_select 不插入来自其他模型的值
【发布时间】:2018-02-10 14:15:18
【问题描述】:

我有两个模型,RoasterRoast

我想让用户从Roaster 模型中选择:roaster 的值。我正在使用一个collection_select,它在下拉菜单中显示烘焙器列表,但它不会将值插入表中。从控制台看,它实际上似乎是在尝试传递 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') %>

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

我的烤参数

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

【问题讨论】:

  • 能否请您发布 ERB 中的完整表格以及控制器端代码
  • 我刚刚添加了新表单。您在其余部分中寻找什么?
  • 你检查了roast.valid吗?在控制器中的新方法中。一旦你检查有效?您将在顶部看到错误消息,您检查了roast.errors.full_messages
  • 是的,它告诉我“roaster”不能为空。这是有道理的,因为我可以看到我没有传递值。
  • 我怀疑你有belongs_to:Roast 模型中的roaster,Roast 模型有roaster_id 作为列

标签: ruby-on-rails collection-select


【解决方案1】:

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

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,以便保存对这些模型的引用。

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

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

您不需要烤肉、烘焙机、国家名称、地区名称。您需要国家的 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') %>

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

【讨论】:

  • 感谢@Pablo 我确实有Roast belongs_to :roaster 我想我在其他问题中为了简洁而忽略了这一点。另外,我要求用户插入 countriesregions 的值,因为我不知道所有可能的值。一旦数据库增长,我很可能会在将来将其更改为从他们的表中选择。我的问题是现在我可以创建一个新的 Roast,但是 Roaster 保存了一些 id 值,例如#&lt;Roaster:0x007fba9a43b500&gt; 而不是字符串。我可以在 Roasts 的 db 表中看到,Roaster 列是空白的。
  • 我理解您所说的国家和地区。在 Roasts 的数据库中,roaster 列是roaster_id?你还有什么和烤肉有关的吗?您不需要 .permit(:roaster..... 在参数中。只是roaster_id。
  • 在 Roasts 表中,我有一栏是烘焙机的名称,即:roaster:char varying,还有:roaster_id:integer。我可以看到我正在为roaster_id 插入一个整数,但不是为roaster 插入一个字符串。我显然想在我的显示视图中显示roaster:string
  • 但是 Roaster 在另一个表中(您从 Roaster 模型中选择表单中的烘焙器,然后将 bakeer_id 传递给控制器​​)​​。您不必将名称保存在 Roast 数据库中。只是roaster_id。名字是@roast.roaster.name
  • 啊当然!出于某种原因,从选择中这样做让我感到困惑。仍然非常熟悉相关模型。实际上,在我的节目视图中 @roast.roaster.roaster_name 有效,但您的观点是正确的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多