collection_select 没有从其他模型中插入值
collection_select not inserting value from other model
我有两个模型,Roaster
和 Roast
我想让用户 select 在 Roaster
模型的新烘焙形式中获得 :roaster
的值。我正在使用 collection_select,它可以在下拉列表中显示烘焙商列表,但它不会将值插入 table。从控制台看,它实际上看起来像是在尝试传递 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"}
我的select:
<%= 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
我认为你做错了很多事。通过查看您的其他问题,我看到了您的模型。我放一些重要的东西:
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
在这些模型中我没有看到烘焙机。我假设 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
你不需要烤肉,烤肉机,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') %>
其实这个比较难,因为一个地区属于一个国家,但是这里显示的是所有地区。您应该只显示所选国家/地区的区域(这是动态的)。
我有两个模型,Roaster
和 Roast
我想让用户 select 在 Roaster
模型的新烘焙形式中获得 :roaster
的值。我正在使用 collection_select,它可以在下拉列表中显示烘焙商列表,但它不会将值插入 table。从控制台看,它实际上看起来像是在尝试传递 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"}
我的select:
<%= 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
我认为你做错了很多事。通过查看您的其他问题,我看到了您的模型。我放一些重要的东西:
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
在这些模型中我没有看到烘焙机。我假设 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
你不需要烤肉,烤肉机,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') %>
其实这个比较难,因为一个地区属于一个国家,但是这里显示的是所有地区。您应该只显示所选国家/地区的区域(这是动态的)。