Rails 5 Collection Выбрать не сохраняющий идентификатор / Выбрать значение параметра
Я делаю приложение для управления графическим дизайном. В приложении у дизайнера есть много рабочих мест, и каждая работа принадлежит дизайнеру. Кажется достаточно простым.
Проблема в том, что customer_id не сохраняется при создании нового задания через форму задания с использованием выбора коллекции.
Примечание. Идентификатор присутствует в коллекции выбора при проверке с помощью Chrome (см. Скриншот). Идентификатор просто не сохраняется по какой-то причине.
Чтобы решить эту проблему, я попытался сделать следующее: 1. Скрытое поле в форме задания 2. attr_accessor в модели 3. необходимые параметры в контроллере (метод bottom)
Пока ничего не получалось, и я не знаю почему.
Буду признателен за любые идеи, которые вы можете иметь.
Лучший,
Дэн
Вот код:
МОДЕЛЬ КЛИЕНТА (имеет много рабочих мест)
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
МОДЕЛЬ РАБОТЫ (принадлежит заказчику)
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 %>
DB SCHEMA
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 to /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" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 6], ["LIMIT", 1]]
Unpermitted parameter: :user_id
(0.4ms) BEGIN
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 6], ["LIMIT", 1]]
SQL (2.9ms) INSERT INTO "jobs" ("title", "body", "created_at", "updated_at", "user_id") VALUES ($1, $2, $3, $4, $5) 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)
ПАРАМЫ, РАЗМЕЩЕННЫЕ ДЛЯ КОНТРОЛЛЕРА
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 CONSOLE - СПОСОБ СОХРАНИТЬ ID КЛИЕНТА ДЛЯ РАБОТЫ
irb(main):007:0> **j = Job.last**
Job Load (0.8ms) SELECT "jobs".* FROM "jobs" ORDER BY "jobs"."id" DESC LIMIT $1 [["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" = $1 LIMIT $2 [["id", 6], ["LIMIT", 1]]
SQL (0.7ms) UPDATE "jobs" SET "updated_at" = $1, "customer_id" = $2 WHERE "jobs"."id" = $3 [["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>
1 ответ
По вашему мнению, вы заполняете поле с именем customer
и скрытое поле customer_id
,
Удалите скрытое поле, вы установите его @job.customer_id
который всегда равен нулю для новой работы, так что вы всегда будете экономить ноль. 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]
эффективно снова закрывая идентификатор клиента
Исправьте эти два, и вы готовы. Я создал PR, чтобы вы могли продолжить.