Ruby on rails Rails表单集合\u选择不保存到数据库
我是rails新手,正在构建一个小应用程序来帮助我的工作 我有客户,网站和报价模型和控制器与视图设置 我在quote模型上创建了一个表单,它从collection_select字段中的其他两个模型中提取数据。我发现的有关rails的collection_select的文档非常糟糕。我想获取客户名称和站点名称,并在报价单上关联/显示该名称 我已经在表单中设置了它,但它不会保存或显示数据 我真的很想了解集合的输入,因为我确信我的输入可能是错误的,并导致了问题 请为站点选择一个客户端}%> 我做了一些研究,从@juanpasta那里学到了这一点 我的表格看起来是这样的 quotes/views/_form.htmlRuby on rails Rails表单集合\u选择不保存到数据库,ruby-on-rails,ruby,collection-select,Ruby On Rails,Ruby,Collection Select,我是rails新手,正在构建一个小应用程序来帮助我的工作 我有客户,网站和报价模型和控制器与视图设置 我在quote模型上创建了一个表单,它从collection_select字段中的其他两个模型中提取数据。我发现的有关rails的collection_select的文档非常糟糕。我想获取客户名称和站点名称,并在报价单上关联/显示该名称 我已经在表单中设置了它,但它不会保存或显示数据 我真的很想了解集合的输入,因为我确信我的输入可能是错误的,并导致了问题 请为站点选择一个客户端}%> 我做了一些
<%= form_for(quote) do |f| %>
<% if quote.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(quote.errors.count, "error") %> prohibited this quote from being saved:</h2><ul>
<% quote.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %><div class="field">
<%= f.label :client %>
<%= f.collection_select :client, Client.all, :quote_client, :client_name , {:prompt => "Please select a client for the site"} %>
</div><div class="field">
<%= f.label :site_name %>
<%= f.collection_select :site, Site.all, :quote_site, :site_name , {:prompt => "Please select a site for the quote"} %>
</div><div class="field">
<%= f.label :quote_contact %>
<%= f.text_field :quote_contact %>
</div><div class="field">
<%= f.label :quote_value %>
<%= f.text_field :quote_value %>
</div><div class="field">
<%= f.label :quote_description %>
<%= f.text_field :quote_description %>
</div><div class="actions">
<%= f.submit %>
</div>
<% end %>
编辑
答复/澄清
Quotes只能有一个客户端和一个站点。该网站也必须属于客户
我有一个通过Client.all从客户端模型调用的客户端列表,以及一个通过Site.all从站点模型调用的站点列表。我只需要一个客户和每个报价一个网站的名称,但希望能够在一个级联的方式选择。选择客户端,然后从客户端可用的站点中选择站点
三个模型之间建立了如下关系:
class Quote < ApplicationRecord
belongs_to :site, optional: true
belongs_to :client, optional: true
has_and_belongs_to_many :assets
end
class Site < ApplicationRecord
has_attached_file :site_image, styles: { small: "64x64", med: "100x100", large: "200x200" }
do_not_validate_attachment_file_type :site_image
belongs_to :client , optional: true
has_and_belongs_to_many :assets
has_and_belongs_to_many :quotes
end
class Client < ApplicationRecord
has_and_belongs_to_many :sites
has_and_belongs_to_many :assets
has_and_belongs_to_many :quotes
end
控制器
class QuotesController < ApplicationController
before_action :set_quote, only: [:show, :edit, :update, :destroy]
# GET /quotes
# GET /quotes.json
def index
@quotes = Quote.all
end
# GET /quotes/1
# GET /quotes/1.json
def show
end
# GET /quotes/new
def new
@quote = Quote.new
end
# GET /quotes/1/edit
def edit
end
# POST /quotes
# POST /quotes.json
def create
@quote = Quote.new(quote_params)
respond_to do |format|
if @quote.save
format.html { redirect_to @quote, notice: 'Quote was successfully created.' }
format.json { render :show, status: :created, location: @quote }
else
format.html { render :new }
format.json { render json: @quote.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /quotes/1
# PATCH/PUT /quotes/1.json
def update
respond_to do |format|
if @quote.update(quote_params)
format.html { redirect_to @quote, notice: 'Quote was successfully updated.' }
format.json { render :show, status: :ok, location: @quote }
else
format.html { render :edit }
format.json { render json: @quote.errors, status: :unprocessable_entity }
end
end
end
# DELETE /quotes/1
# DELETE /quotes/1.json
def destroy
@quote.destroy
respond_to do |format|
format.html { redirect_to quotes_url, notice: 'Quote was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_quote
@quote = Quote.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def quote_params
params.require(:quote).permit(:quote_client, :quote_site, :client_name, :site_name, :quote_contact, :quote_value, :quote_description)
end
end
class SitesController < ApplicationController
before_action :set_site, only: [:show, :edit, :update, :destroy]
# GET /sites
# GET /sites.json
def index
@sites = Site.all
@clients = Client.all
end
# GET /sites/1
# GET /sites/1.json
def show
@sites = Site.all
@clients = Client.all
end
# GET /sites/new
def new
@site = Site.new
end
# GET /sites/1/edit
def edit
end
# POST /sites
# POST /sites.json
def create
@site = Site.new(site_params)
respond_to do |format|
if @site.save
format.html { redirect_to @site, notice: 'Site was successfully created.' }
format.json { render :show, status: :created, location: @site }
else
format.html { render :new }
format.json { render json: @site.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /sites/1
# PATCH/PUT /sites/1.json
def update
respond_to do |format|
if @site.update(site_params)
format.html { redirect_to @site, notice: 'Site was successfully updated.' }
format.json { render :show, status: :ok, location: @site }
else
format.html { render :edit }
format.json { render json: @site.errors, status: :unprocessable_entity }
end
end
end
# DELETE /sites/1
# DELETE /sites/1.json
def destroy
@site.destroy
respond_to do |format|
format.html { redirect_to sites_url, notice: 'Site was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_site
@site = Site.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def site_params
params.require(:site).permit(:site_client, :client_name, :site_name, :site_image, :site_address, :site_contact)
end
end
class ClientsController < ApplicationController
before_action :set_client, only: [:show, :edit, :update, :destroy]
# GET /clients
# GET /clients.json
def index
@clients = Client.all
@sites = Site.all
end
# GET /clients/1
# GET /clients/1.json
def show
@clients = Client.all
@sites = Site.all
end
# GET /clients/new
def new
@client = Client.new
end
# GET /clients/1/edit
def edit
end
# POST /clients
# POST /clients.json
def create
@client = Client.new(client_params)
respond_to do |format|
if @client.save
format.html { redirect_to @client, notice: 'Client was successfully created.' }
format.json { render :show, status: :created, location: @client }
else
format.html { render :new }
format.json { render json: @client.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /clients/1
# PATCH/PUT /clients/1.json
def update
respond_to do |format|
if @client.update(client_params)
format.html { redirect_to @client, notice: 'Client was successfully updated.' }
format.json { render :show, status: :ok, location: @client }
else
format.html { render :edit }
format.json { render json: @client.errors, status: :unprocessable_entity }
end
end
end
# DELETE /clients/1
# DELETE /clients/1.json
def destroy
@client.destroy
respond_to do |format|
format.html { redirect_to clients_url, notice: 'Client was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_client
@client = Client.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def client_params
params.require(:client).permit(:client_name, :client_address, :client_phone, :client_email, :client_website)
end
end
添加物
您可能会注意到,我已尝试进行缩放,以便在站点和站点中调用客户机,并在报价中调用客户机。首先:我假设您在三个模型之间建立了关系!从报价单到客户,从报价单到现场,必须有很多关系 有两个问题可能会阻止表单保存 首先是你如何创建你的收藏。collection select中的第三个参数是将发送到控制器的内容。这应该是一个ID数组,我假设一个报价可以有多个客户机。我看你管它叫:quote_client。我将其重命名为:client_id。最后,这就是您想要发送给控制器的内容:一个ID数组 你要注意的第二件事是你的控制器。如果您共享了控制器代码就好了,但我假设您有一个quotes\u控制器,其中包含quote\u params方法。它可能会像这样:
def quote_params
params.require(:quote).permit(:quote_contact, etc., etc.)
end
def quote_params
params.require(:quote).permit(:quote_contact, client_ids: [], site_ids: [], all_other_fields...)
end
此控制器方法必须使用您的form_for进行响应,因此form_for like quote_contact中的每个字段都应该在许可证中,否则将无法保存。如果要保存一个ID数组,必须告诉此方法您需要一个ID数组。您可以这样做:客户端ID:[]
因此,新的quote_params方法应如下所示:
def quote_params
params.require(:quote).permit(:quote_contact, etc., etc.)
end
def quote_params
params.require(:quote).permit(:quote_contact, client_ids: [], site_ids: [], all_other_fields...)
end
我希望这个答案能为你提供急需的帮助。如果我需要进一步澄清:只需问:
干杯
编辑:上面的答案仍然适用于那些确实希望保存多条记录的人,但由于您声明您只希望保存一条记录,因此我更新了答案:
我在上面总结的逻辑大致相同
您目前似乎不了解的是表单映射到控制器和控制器映射到数据库的方式,这对于理解Rails应用程序非常重要。如上所述,quote_params方法应允许表单中的所有字段保存到数据库中。这意味着许可部分中的所有字段都应该在数据库中,否则无法保存。如果仔细查看数据库中的quote表,您会发现它包含客户id和站点id字段。这两个字段包含quote/client和quote/site关联的引用。这就是为什么您的许可证目前不起作用,因为您有quote_客户端和quote_站点。数据库没有quote_客户端或quote_站点,因此在尝试保存时不会更新关联。数据库确实有client_id和site_id,因此应该将其传递到quote-params方法中
当然,这应该与表单中的字段相对应。因此,您需要改变两件事来实现这一目标:
更改您选择的两个集合,并将:quote\u客户端替换为:client\u id,将:quote\u站点替换为:site\u id
更改控制器方法以反映表单中的更改。在这里,您还必须将quote_站点和quote_客户端交换为quote_id和site_id,如下所示:
def quote_params
params.require(:quote).permit(:quote_contact, etc., etc.)
end
def quote_params
params.require(:quote).permit(:quote_contact, client_ids: [], site_ids: [], all_other_fields...)
end
def quote_参数
参数要求:报价。许可:客户id、:站点id等。
结束
在使用Rails MODELNAME_params方法(我们称之为强参数->读取它)时要记住的重要一点!
您的表单和许可操作都应该像在数据库中一样列出字段,否则数据库将无法理解,您的记录也无法正确保存
我希望通过这次编辑,你会明白这一点
干杯谢谢@woutronteltap,你已经成为gr
吃吧,帮帮我。我已经为您添加了更多的信息,包括每个的控制器。我已经编辑了关于如何实现您的集合选择问题的帖子,希望您现在能弄明白:其他问题:您能给我看一下您的数据库模式吗?项目中的db/schema.rb。在表单_中,您有类似quote _描述的值,但它不是保存在类似DB的描述中吗?或者您是否将所有字段都命名为_xxx?在这种情况下,这很好,但在我看来,这似乎是一种奇怪的做法。非常感谢您提供的详细信息,我现在明白了,rails实际上正在做很多基础工作,我正试图用我的数据库做这些工作。双重处理。现在我已经尝试了太多不同版本的“请为站点}%>选择一个客户端”,我不知道什么是正确的。我已经更新了所有参数,但现在我得到了未定义的方法:quoteHi@wointerronteltap。请忽略以上。。。经过一点尝试和大量错误之后,它就可以工作并节省成本。再次感谢