Rails 5 Collection Select 不保存 ID / Select 选项值
Rails 5 Collection Select Not Saving ID / Select Option Value
我正在制作一个 rails 应用程序来管理平面设计工作。在应用程序中,一个设计师 has_many 职位,每个职位 belongs_to 一个设计师。看起来很简单。
问题是在使用 collection select 通过作业表单创建新作业时 customer_id 没有保存。
注意 - 当我使用 Chrome 检查时,ID 出现在 collection select 中(见屏幕截图)。由于某种原因,ID 只是没有保存。
为了解决这个问题,我尝试了以下方法:
1. job表单中的隐藏字段
2.模型中的attr_accessor
3.控制器中的必需参数(底部方法)
到目前为止没有任何效果,我也不知道为什么。
如果您有任何见解,我们将不胜感激。
最佳,
段
这是代码:
客户模型(有很多工作)
class Customer < ApplicationRecord
has_many :jobs
attr_accessor :customer_id #this has to be :customer_id, not just :id (fixed the option values not displaying in
#collection_select)
end
JOBS MODEL(属于客户)
class Job < ApplicationRecord
# Only need optional: true on the belongs_to side of the association, not the has_many side.
belongs_to :customer, optional: true
accepts_nested_attributes_for :customer
has_many :notes, as: :noteable
has_many :tasks
belongs_to :user
end
作业控制器
class JobsController < ApplicationController
before_action :set_job, only: [:show, :edit, :update, :destroy]
# Before filter - check if user authenticated. If not, redirect to log in page.
before_action :authenticate_user!
# GET /jobs
# GET /jobs.json
def index
# we aren't building an API, so no need to have users/4/jobs work at all!
# if admin == true @jobs - Job.all
# else
#@user = current_user
#@jobs = @user.jobs
@jobs = Job.all
end
# GET /jobs/1
# GET /jobs/1.json
def show
end
# GET /jobs/new
def new
@job = Job.new
end
# GET /jobs/1/edit
def edit
end
# POST /jobs
# POST /jobs.json
def create
@job = Job.new(job_params)
@customer = @job.customer_id
# Grab the current user ID and populate the @job.user_id
@job.user_id = current_user.id
respond_to do |format|
if @job.save
format.html { redirect_to @job, notice: 'Job was successfully created.' }
format.json { render :show, status: :created, location: @job }
else
format.html { render :new }
format.json { render json: @job.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /jobs/1
# PATCH/PUT /jobs/1.json
def update
respond_to do |format|
if @job.update(job_params)
format.html { redirect_to @job, notice: 'Job was successfully updated.' }
format.json { render :show, status: :ok, location: @job }
else
format.html { render :edit }
format.json { render json: @job.errors, status: :unprocessable_entity }
end
end
end
# DELETE /jobs/1
# DELETE /jobs/1.json
def destroy
@job.destroy
respond_to do |format|
format.html { redirect_to jobs_url, notice: 'Job was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_job
@job = Job.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def job_params
params.require(:job).permit(:title, :body, :customer_id )
#params.require(:customer).permit(:customer_id)
end
end
工作表
<%= form_with(model: job, local: true) do |form| %>
<% if job.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(job.errors.count, "error") %> prohibited this job from being saved:</h2>
<ul>
<% job.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :title %>
<%= form.text_field :title, id: :job_title %>
</div>
<div class="field">
<%= form.label :body %>
<%= form.text_area :body, id: :job_body, size: "120x30" %>
</div>
<div class="field" >
<%= form.label :customer %>
<%= form.collection_select :customer, Customer.all, :id, :name, {:prompt => '-- Select a Customer --'} %>
<%#= form.hidden_field :customer_id, value: @job.customer_id %>
<%= form.hidden_field :customer_id, :value => @job.customer_id %>
</div>
<%= form.hidden_field :user_id %>
<div class="field">
<%#= form.label :user_id %>
<%#= form.text_field :user_id %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
数据库模式
ActiveRecord::Schema.define(version: 20190205062652) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "customers", force: :cascade do |t|
t.string "name"
t.string "email_address"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "jobs", force: :cascade do |t|
t.string "title"
t.text "body"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.bigint "user_id"
t.bigint "customer_id"
t.index ["customer_id"], name: "index_jobs_on_customer_id"
t.index ["user_id"], name: "index_jobs_on_user_id"
end
路线
Rails.application.routes.draw do
resources :customers
devise_for :users
resources :jobs do
resources :customers
resources :tasks
end
resources :tasks do
resources :notes
end
resources :jobs do
resources :notes
end
#This needs to be here, otherwise error (as notes resource didn't exist on its own)
resources :notes
resources :users do
resources :jobs
end
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
authenticated :user do
root :to => "jobs#index"
end
unauthenticated :user do
devise_scope :user do
get "/" => "devise/sessions#new"
end
end
end
编辑 - 这是 POST 到 /jobs for Jobs#Create
的服务器日志条目
Started POST "/jobs" for 127.0.0.1 at 2019-02-05 16:21:46 -0800
Processing by JobsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"tzPFtpJ3NJZmFF4/X7NyXmGwfrv1jqGaiIbQirM8AEIJqqddrLPdo20AWhR4McOlI8TKRCsELfJnh+busfi1hA==", "job"=>{"title"=>"aaa", "body"=>"aaa", "customer_id"=>"", "user_id"=>""}, "commit"=>"Create Job"}
User Load (0.7ms) SELECT "users".* FROM "users" WHERE "users"."id" = ORDER BY "users"."id" ASC LIMIT [["id", 6], ["LIMIT", 1]]
Unpermitted parameter: :user_id
(0.4ms) BEGIN
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = LIMIT [["id", 6], ["LIMIT", 1]]
SQL (2.9ms) INSERT INTO "jobs" ("title", "body", "created_at", "updated_at", "user_id") VALUES (, , , , ) RETURNING "id" [["title", "aaa"], ["body", "aaa"], ["created_at", "2019-02-06 00:21:46.350382"], ["updated_at", "2019-02-06 00:21:46.350382"], ["user_id", 6]]
(2.4ms) COMMIT
Redirected to http://localhost:3000/jobs/49
Completed 302 Found in 18ms (ActiveRecord: 6.7ms)
参数POSTED到控制器
Parameters: {"utf8"=>"✓", "authenticity_token"=>"tzPFtpJ3NJZmFF4/X7NyXmGwfrv1jqGaiIbQirM8AEIJqqddrLPdo20AWhR4McOlI8TKRCsELfJnh+busfi1hA==", "job"=>{"title"=>"aaa", "body"=>"aaa", "customer_id"=>"", "user_id"=>""}, "commit"=>"Create Job"}
编辑:HTML 新工作表的页面源代码
<p class="notice"></p>
<p class="alert"></p>
<h1>New Job</h1>
<form action="/jobs" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓" /><input type="hidden" name="authenticity_token" value="7i4b/dij53rntbjpYnzIvH2lv+sCzdyQ+B7U6fYEeAlQt3kW5mcOT+yhvMJF/nlHP9ELFNxHUPgXH+KN9MDNzw==" />
<div class="field">
<label for="job_title">Title</label>
<input id="job_title" type="text" name="job[title]" />
</div>
<div class="field">
<label for="job_body">Body</label>
<textarea id="job_body" name="job[body]" cols="120" rows="30">
</textarea>
</div>
<div class="field" >
<label for="job_customer">Customer</label>
<select name="job[customer_id]"><option value="">-- Select a Customer --</option>
<option value="1">Nathan Wawruck </option>
<option value="2">Martin Jenkins</option>
</div>
<div class="actions">
<input type="submit" name="commit" value="Create Job" data-disable-with="Create Job" />
</div>
</form>
<a href="/jobs">Back</a>
编辑 - RAILS 控制台 - 能够为作业保存客户 ID
irb(main):007:0> **j = Job.last**
Job Load (0.8ms) SELECT "jobs".* FROM "jobs" ORDER BY "jobs"."id" DESC LIMIT [["LIMIT", 1]]
=> #<Job id: 62, title: "aaa", body: "aaa", created_at: "2019-02-07 03:27:17", updated_at: "2019-02-07 03:27:17", user_id: 6, **customer_id: nil**>
irb(main):008:0> **j.customer_id = 2**
=> 2
irb(main):009:0> **j.save**
(0.3ms) BEGIN
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = LIMIT [["id", 6], ["LIMIT", 1]]
SQL (0.7ms) UPDATE "jobs" SET "updated_at" = , "customer_id" = WHERE "jobs"."id" = [["updated_at", "2019-02-07 03:27:45.317996"], [**"customer_id", 2**], ["id", 62]]
(2.3ms) COMMIT
=> **true**
irb(main):010:0> **j**
=> #<Job id: 62, title: "aaa", body: "aaa", created_at: "2019-02-07 03:27:17", updated_at: "2019-02-07 03:27:45", user_id: 6, **customer_id: 2**>
irb(main):011:0>
在您看来,您填写了一个名为 customer
的字段和一个隐藏字段 customer_id
。
删除隐藏字段,将其设置为 @job.customer_id
对于新工作而言始终为 nil,因此您将始终保存 nil。 customer
字段将被强参数拒绝。
调整视图如下:
<div class="field" >
<%= form.label :customer %>
<%= form.collection_select :customer_id, Customer.all, :id, :name, {:prompt => '-- Select a Customer --'} %>
</div>
[编辑]
查看您的存储库,我可以看到
- 您的视图代码中有更多隐藏字段,实际上仍然空白
customer_id
- 在您的控制器中,您还设置了
customer_id = params[:customer_id]
,有效地再次消隐了客户 ID
解决这两个问题,您就可以开始了。我创建了一个 PR,所以你现在应该可以继续了。
我正在制作一个 rails 应用程序来管理平面设计工作。在应用程序中,一个设计师 has_many 职位,每个职位 belongs_to 一个设计师。看起来很简单。
问题是在使用 collection select 通过作业表单创建新作业时 customer_id 没有保存。
注意 - 当我使用 Chrome 检查时,ID 出现在 collection select 中(见屏幕截图)。由于某种原因,ID 只是没有保存。
为了解决这个问题,我尝试了以下方法: 1. job表单中的隐藏字段 2.模型中的attr_accessor 3.控制器中的必需参数(底部方法)
到目前为止没有任何效果,我也不知道为什么。
如果您有任何见解,我们将不胜感激。
最佳,
段
这是代码:
客户模型(有很多工作)
class Customer < ApplicationRecord
has_many :jobs
attr_accessor :customer_id #this has to be :customer_id, not just :id (fixed the option values not displaying in
#collection_select)
end
JOBS MODEL(属于客户)
class Job < ApplicationRecord
# Only need optional: true on the belongs_to side of the association, not the has_many side.
belongs_to :customer, optional: true
accepts_nested_attributes_for :customer
has_many :notes, as: :noteable
has_many :tasks
belongs_to :user
end
作业控制器
class JobsController < ApplicationController
before_action :set_job, only: [:show, :edit, :update, :destroy]
# Before filter - check if user authenticated. If not, redirect to log in page.
before_action :authenticate_user!
# GET /jobs
# GET /jobs.json
def index
# we aren't building an API, so no need to have users/4/jobs work at all!
# if admin == true @jobs - Job.all
# else
#@user = current_user
#@jobs = @user.jobs
@jobs = Job.all
end
# GET /jobs/1
# GET /jobs/1.json
def show
end
# GET /jobs/new
def new
@job = Job.new
end
# GET /jobs/1/edit
def edit
end
# POST /jobs
# POST /jobs.json
def create
@job = Job.new(job_params)
@customer = @job.customer_id
# Grab the current user ID and populate the @job.user_id
@job.user_id = current_user.id
respond_to do |format|
if @job.save
format.html { redirect_to @job, notice: 'Job was successfully created.' }
format.json { render :show, status: :created, location: @job }
else
format.html { render :new }
format.json { render json: @job.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /jobs/1
# PATCH/PUT /jobs/1.json
def update
respond_to do |format|
if @job.update(job_params)
format.html { redirect_to @job, notice: 'Job was successfully updated.' }
format.json { render :show, status: :ok, location: @job }
else
format.html { render :edit }
format.json { render json: @job.errors, status: :unprocessable_entity }
end
end
end
# DELETE /jobs/1
# DELETE /jobs/1.json
def destroy
@job.destroy
respond_to do |format|
format.html { redirect_to jobs_url, notice: 'Job was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_job
@job = Job.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def job_params
params.require(:job).permit(:title, :body, :customer_id )
#params.require(:customer).permit(:customer_id)
end
end
工作表
<%= form_with(model: job, local: true) do |form| %>
<% if job.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(job.errors.count, "error") %> prohibited this job from being saved:</h2>
<ul>
<% job.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :title %>
<%= form.text_field :title, id: :job_title %>
</div>
<div class="field">
<%= form.label :body %>
<%= form.text_area :body, id: :job_body, size: "120x30" %>
</div>
<div class="field" >
<%= form.label :customer %>
<%= form.collection_select :customer, Customer.all, :id, :name, {:prompt => '-- Select a Customer --'} %>
<%#= form.hidden_field :customer_id, value: @job.customer_id %>
<%= form.hidden_field :customer_id, :value => @job.customer_id %>
</div>
<%= form.hidden_field :user_id %>
<div class="field">
<%#= form.label :user_id %>
<%#= form.text_field :user_id %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
数据库模式
ActiveRecord::Schema.define(version: 20190205062652) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "customers", force: :cascade do |t|
t.string "name"
t.string "email_address"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "jobs", force: :cascade do |t|
t.string "title"
t.text "body"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.bigint "user_id"
t.bigint "customer_id"
t.index ["customer_id"], name: "index_jobs_on_customer_id"
t.index ["user_id"], name: "index_jobs_on_user_id"
end
路线
Rails.application.routes.draw do
resources :customers
devise_for :users
resources :jobs do
resources :customers
resources :tasks
end
resources :tasks do
resources :notes
end
resources :jobs do
resources :notes
end
#This needs to be here, otherwise error (as notes resource didn't exist on its own)
resources :notes
resources :users do
resources :jobs
end
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
authenticated :user do
root :to => "jobs#index"
end
unauthenticated :user do
devise_scope :user do
get "/" => "devise/sessions#new"
end
end
end
编辑 - 这是 POST 到 /jobs for Jobs#Create
的服务器日志条目Started POST "/jobs" for 127.0.0.1 at 2019-02-05 16:21:46 -0800
Processing by JobsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"tzPFtpJ3NJZmFF4/X7NyXmGwfrv1jqGaiIbQirM8AEIJqqddrLPdo20AWhR4McOlI8TKRCsELfJnh+busfi1hA==", "job"=>{"title"=>"aaa", "body"=>"aaa", "customer_id"=>"", "user_id"=>""}, "commit"=>"Create Job"}
User Load (0.7ms) SELECT "users".* FROM "users" WHERE "users"."id" = ORDER BY "users"."id" ASC LIMIT [["id", 6], ["LIMIT", 1]]
Unpermitted parameter: :user_id
(0.4ms) BEGIN
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = LIMIT [["id", 6], ["LIMIT", 1]]
SQL (2.9ms) INSERT INTO "jobs" ("title", "body", "created_at", "updated_at", "user_id") VALUES (, , , , ) RETURNING "id" [["title", "aaa"], ["body", "aaa"], ["created_at", "2019-02-06 00:21:46.350382"], ["updated_at", "2019-02-06 00:21:46.350382"], ["user_id", 6]]
(2.4ms) COMMIT
Redirected to http://localhost:3000/jobs/49
Completed 302 Found in 18ms (ActiveRecord: 6.7ms)
参数POSTED到控制器
Parameters: {"utf8"=>"✓", "authenticity_token"=>"tzPFtpJ3NJZmFF4/X7NyXmGwfrv1jqGaiIbQirM8AEIJqqddrLPdo20AWhR4McOlI8TKRCsELfJnh+busfi1hA==", "job"=>{"title"=>"aaa", "body"=>"aaa", "customer_id"=>"", "user_id"=>""}, "commit"=>"Create Job"}
编辑:HTML 新工作表的页面源代码
<p class="notice"></p>
<p class="alert"></p>
<h1>New Job</h1>
<form action="/jobs" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓" /><input type="hidden" name="authenticity_token" value="7i4b/dij53rntbjpYnzIvH2lv+sCzdyQ+B7U6fYEeAlQt3kW5mcOT+yhvMJF/nlHP9ELFNxHUPgXH+KN9MDNzw==" />
<div class="field">
<label for="job_title">Title</label>
<input id="job_title" type="text" name="job[title]" />
</div>
<div class="field">
<label for="job_body">Body</label>
<textarea id="job_body" name="job[body]" cols="120" rows="30">
</textarea>
</div>
<div class="field" >
<label for="job_customer">Customer</label>
<select name="job[customer_id]"><option value="">-- Select a Customer --</option>
<option value="1">Nathan Wawruck </option>
<option value="2">Martin Jenkins</option>
</div>
<div class="actions">
<input type="submit" name="commit" value="Create Job" data-disable-with="Create Job" />
</div>
</form>
<a href="/jobs">Back</a>
编辑 - RAILS 控制台 - 能够为作业保存客户 ID
irb(main):007:0> **j = Job.last**
Job Load (0.8ms) SELECT "jobs".* FROM "jobs" ORDER BY "jobs"."id" DESC LIMIT [["LIMIT", 1]]
=> #<Job id: 62, title: "aaa", body: "aaa", created_at: "2019-02-07 03:27:17", updated_at: "2019-02-07 03:27:17", user_id: 6, **customer_id: nil**>
irb(main):008:0> **j.customer_id = 2**
=> 2
irb(main):009:0> **j.save**
(0.3ms) BEGIN
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = LIMIT [["id", 6], ["LIMIT", 1]]
SQL (0.7ms) UPDATE "jobs" SET "updated_at" = , "customer_id" = WHERE "jobs"."id" = [["updated_at", "2019-02-07 03:27:45.317996"], [**"customer_id", 2**], ["id", 62]]
(2.3ms) COMMIT
=> **true**
irb(main):010:0> **j**
=> #<Job id: 62, title: "aaa", body: "aaa", created_at: "2019-02-07 03:27:17", updated_at: "2019-02-07 03:27:45", user_id: 6, **customer_id: 2**>
irb(main):011:0>
在您看来,您填写了一个名为 customer
的字段和一个隐藏字段 customer_id
。
删除隐藏字段,将其设置为 @job.customer_id
对于新工作而言始终为 nil,因此您将始终保存 nil。 customer
字段将被强参数拒绝。
调整视图如下:
<div class="field" >
<%= form.label :customer %>
<%= form.collection_select :customer_id, Customer.all, :id, :name, {:prompt => '-- Select a Customer --'} %>
</div>
[编辑]
查看您的存储库,我可以看到
- 您的视图代码中有更多隐藏字段,实际上仍然空白
customer_id
- 在您的控制器中,您还设置了
customer_id = params[:customer_id]
,有效地再次消隐了客户 ID
解决这两个问题,您就可以开始了。我创建了一个 PR,所以你现在应该可以继续了。