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="&#x2713;" /><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,所以你现在应该可以继续了。