Rails collection_select not working for many to one relationship - ruby-on-rails

I have 3 models in my rails project
Patient
class Patient < ActiveRecord::Base
has_many :temperatures
belongs_to :bloodgroup
def fullname
"#{firstName} #{surname}"
end
end
Temperature
class Temperature < ActiveRecord::Base
belongs_to :patient
end
BloodGroup
class BloodGroup < ActiveRecord::Base
has_many :patients
end
collection_select works for adding a patient to a temperature using the below snippet
<div class="field">
<%= f.label :patient_id %><br>
<%= collection_select(:temperature, :patient_id, Patient.all, :id, :fullname, prompt: true) %>
</div>
however the below snippet - to add BloodGroup to a patient doesnt work
<div class="field">
<%= f.label :bloodgroup_id %><br>
<%= collection_select(:Patient, :bloodgroup_id, BloodGroup.all, :id, :id, prompt: true) %>
</div>
I'm not sure if I've not set up the collection_select properly or if I've not set up the association properly as I'm new to rails so any help would be greatly appreciated.
Update
create_table "blood_groups", force: :cascade do |t|
t.string "bloodgroup"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "patients", force: :cascade do |t|
t.string "firstName"
t.string "surname"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "bloodgroup_id"
end
create_table "temperatures", force: :cascade do |t|
t.integer "patient_id"
t.decimal "temperature"
t.datetime "dt"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Controllers
Patient
class PatientsController < ApplicationController
before_action :set_patient, only: [:show, :edit, :update, :destroy]
# GET /patients
# GET /patients.json
def index
#patients = Patient.all
end
# GET /patients/1
# GET /patients/1.json
def show
end
# GET /patients/new
def new
#patient = Patient.new
end
# GET /patients/1/edit
def edit
end
# POST /patients
# POST /patients.json
def create
#patient = Patient.new(patient_params)
respond_to do |format|
if #patient.save
format.html { redirect_to #patient, notice: 'Patient was successfully created.' }
format.json { render :show, status: :created, location: #patient }
else
format.html { render :new }
format.json { render json: #patient.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /patients/1
# PATCH/PUT /patients/1.json
def update
respond_to do |format|
if #patient.update(patient_params)
format.html { redirect_to #patient, notice: 'Patient was successfully updated.' }
format.json { render :show, status: :ok, location: #patient }
else
format.html { render :edit }
format.json { render json: #patient.errors, status: :unprocessable_entity }
end
end
end
# DELETE /patients/1
# DELETE /patients/1.json
def destroy
#patient.destroy
respond_to do |format|
format.html { redirect_to patients_url, notice: 'Patient was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_patient
#patient = Patient.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def patient_params
params.require(:patient).permit(:firstName, :surname)
end
end
Temperature
class TemperaturesController < ApplicationController
before_action :set_temperature, only: [:show, :edit, :update, :destroy]
# GET /temperatures
# GET /temperatures.json
def index
#temperatures = Temperature.all
end
# GET /temperatures/1
# GET /temperatures/1.json
def show
end
# GET /temperatures/new
def new
#temperature = Temperature.new
end
# GET /temperatures/1/edit
def edit
end
# POST /temperatures
# POST /temperatures.json
def create
#temperature = Temperature.new(temperature_params)
respond_to do |format|
if #temperature.save
format.html { redirect_to #temperature, notice: 'Temperature was successfully created.' }
format.json { render :show, status: :created, location: #temperature }
else
format.html { render :new }
format.json { render json: #temperature.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /temperatures/1
# PATCH/PUT /temperatures/1.json
def update
respond_to do |format|
if #temperature.update(temperature_params)
format.html { redirect_to #temperature, notice: 'Temperature was successfully updated.' }
format.json { render :show, status: :ok, location: #temperature }
else
format.html { render :edit }
format.json { render json: #temperature.errors, status: :unprocessable_entity }
end
end
end
# DELETE /temperatures/1
# DELETE /temperatures/1.json
def destroy
#temperature.destroy
respond_to do |format|
format.html { redirect_to temperatures_url, notice: 'Temperature was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_temperature
#temperature = Temperature.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def temperature_params
params.require(:temperature).permit(:patient_id, :temperature, :dt)
end
end
Blood Group
class BloodGroupsController < ApplicationController
before_action :set_blood_group, only: [:show, :edit, :update, :destroy]
# GET /blood_groups
# GET /blood_groups.json
def index
#blood_groups = BloodGroup.all
end
# GET /blood_groups/1
# GET /blood_groups/1.json
def show
end
# GET /blood_groups/new
def new
#blood_group = BloodGroup.new
end
# GET /blood_groups/1/edit
def edit
end
# POST /blood_groups
# POST /blood_groups.json
def create
#blood_group = BloodGroup.new(blood_group_params)
respond_to do |format|
if #blood_group.save
format.html { redirect_to #blood_group, notice: 'Blood group was successfully created.' }
format.json { render :show, status: :created, location: #blood_group }
else
format.html { render :new }
format.json { render json: #blood_group.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /blood_groups/1
# PATCH/PUT /blood_groups/1.json
def update
respond_to do |format|
if #blood_group.update(blood_group_params)
format.html { redirect_to #blood_group, notice: 'Blood group was successfully updated.' }
format.json { render :show, status: :ok, location: #blood_group }
else
format.html { render :edit }
format.json { render json: #blood_group.errors, status: :unprocessable_entity }
end
end
end
# DELETE /blood_groups/1
# DELETE /blood_groups/1.json
def destroy
#blood_group.destroy
respond_to do |format|
format.html { redirect_to blood_groups_url, notice: 'Blood group was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_blood_group
#blood_group = BloodGroup.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def blood_group_params
params.require(:blood_group).permit(:bloodgroup)
end
end
Log
Started POST "/patients" for 81.144.132.166 at 2017-08-25 12:10:08 +0000
Cannot render console from 81.144.132.166! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by PatientsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"KnDRbEAL/f1DK6Gc9TcFNu0rRH5tahnGZiwLcx6FqH5iP7L5BsMOjH0yKR3630g/4ejCLUzilloj1rkO86wkAA==", "patient"=>{"firstName"=>"Test", "surname"=>"test", "bloodgroup_id"=>"7"}, "commit"=>"Create Patient"}
Unpermitted parameter: bloodgroup_id
(0.1ms) begin transaction
SQL (41.7ms) INSERT INTO "patients" ("firstName", "surname", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["firstName", "Test"], ["surname", "test"], ["created_at", "2017-08-25 12:10:08.979026"], ["updated_at", "2017-08-25 12:10:08.979026"]]
(10.1ms) commit transaction
Redirected to https://healthy-rails-conorsmalley.c9users.io/patients/6
Completed 302 Found in 125ms (ActiveRecord: 51.8ms)
Started GET "/patients/6" for 81.144.132.166 at 2017-08-25 12:10:09 +0000
Cannot render console from 81.144.132.166! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by PatientsController#show as HTML
Parameters: {"id"=>"6"}
Patient Load (0.4ms) SELECT "patients".* FROM "patients" WHERE "patients"."id" = ? LIMIT 1 [["id", 6]]
Rendered patients/show.html.erb within layouts/application (0.4ms)
Completed 200 OK in 32ms (Views: 29.2ms | ActiveRecord: 0.4ms)
When I press submit to add bloodgroup to a patient i get the following logs
Started POST "/patients" for 81.144.132.166 at 2017-08-25 12:40:03 +0000
Cannot render console from 81.144.132.166! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by PatientsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Mkw0f3Yu6jXqzc+wBgbLxDDbW8GJY41ARBme0St/JIV6A1fqMOYZRNTURzEJ7obNPBjdkqjrAtwB4yysxlao+w==", "patient"=>{"firstName"=>"asdf", "surname"=>"ghjk"}, "Patient"=>{"bloodgroup_id"=>"3"}, "commit"=>"Create Patient"}
(0.1ms) begin transaction
SQL (0.4ms) INSERT INTO "patients" ("firstName", "surname", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["firstName", "asdf"], ["surname", "ghjk"], ["created_at", "2017-08-25 12:40:03.623102"], ["updated_at", "2017-08-25 12:40:03.623102"]]
(9.6ms) commit transaction
Redirected to https://healthy-rails-conorsmalley.c9users.io/patients/8
Completed 302 Found in 15ms (ActiveRecord: 10.2ms)
Started GET "/patients/8" for 81.144.132.166 at 2017-08-25 12:40:03 +0000
Cannot render console from 81.144.132.166! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by PatientsController#show as HTML
Parameters: {"id"=>"8"}
Patient Load (0.2ms) SELECT "patients".* FROM "patients" WHERE "patients"."id" = ? LIMIT 1 [["id", 8]]
Rendered patients/show.html.erb within layouts/application (0.5ms)
Completed 200 OK in 23ms (Views: 21.4ms | ActiveRecord: 0.2ms)

You have a few mistakes in your code which would be causing the problem
1)
belongs_to :bloodgroup
should be
belongs_to :blood_group
as the model name is BloodGroup and the snake_case string of BloodGroup is blood_group not bloodgroup
2)
<%= collection_select(:Patient, :bloodgroup_id, BloodGroup.all, :id, :id, prompt: true) %>
should be
<%= collection_select(:patient, :blood_group_id, BloodGroup.all, :id, :id, prompt: true) %>
Update:
My db schema has the column bloodgroup_id not blood_group_id
Then you need to specify your association with a custom foreign key else by default Rails will look for blood_group_id
class Patient < ActiveRecord::Base
has_many :temperatures
belongs_to :blood_group, foreign_key: "bloodgroup_id"
def fullname
"#{firstName} #{surname}"
end
end
Unpermitted parameter: bloodgroup_id
You need to permit bloodgroup_id in the patient_params in order to save it to the DB
def patient_params
params.require(:patient).permit(:firstName, :surname, bloodgroup_id)
end

Related

Rails join table not saving

Hi I am playing around in rails and have built a little listing application.
My application has a listing model that has many tags through a has and belongs to many join table.
the join table is called listings_tags
The problem I have is that I cannot save the listing_tag association during create or update.
I can see in console
Started PATCH "/listings/92" for 127.0.0.1 at 2018-08-15 12:45:58 +1000
Processing by ListingsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"5isdLs2FiToZxtm1ZVPP0y0lKtnfyoLA8Njv4GBwWVH1M3TIm2IUW9ts5RR06OpQz8tgSBitZ7Rm69uVIifevQ==", "listing"=>{"name"=>"Canteen Coffee", "streetAddres"=>"19 Park Avenue", "suburb_id"=>"31", "post_code_id"=>"2", "region_id"=>"1", "country_id"=>"2", "telephone"=>"+61416650204", "url"=>"http://canteencoffee.com.au/canteen-kitchen/", "tag_ids"=>["", "1"]}, "commit"=>"Update Listing", "id"=>"92"}
Listing Load (0.2ms) SELECT "listings".* FROM "listings" WHERE "listings"."id" = $1 LIMIT $2 [["id", 92], ["LIMIT", 1]]
Unpermitted parameter: :tag_ids
(1.8ms) BEGIN
Suburb Load (5.4ms) SELECT "suburbs".* FROM "suburbs" WHERE "suburbs"."id" = $1 LIMIT $2 [["id", 31], ["LIMIT", 1]]
(1.7ms) COMMIT
Redirected to http://localhost:3000/listings/92
Completed 302 Found in 21ms (ActiveRecord: 9.0ms)
Obviously my issue is the :tag_ids
so I tried changing my listing params.require(:listing).permit() to include listing_attributes: [:id], tags: [:id] and :tag_ids
its killing me :) please help
Listing Model
class Listing < ApplicationRecord
has_and_belongs_to_many :tags
belongs_to :suburb
has_one :post_code, through: :suburb
accepts_nested_attributes_for :tags
def self.search(term)
if term
where('name LIKE ?', "%#{term}%")
else
order('id DESC')
end
end
end
Tag Model
class Tag < ApplicationRecord
has_and_belongs_to_many :listings
end
Listings Tags Schema
create_table "listings_tags", id: false, force: :cascade do |t|
t.bigint "listing_id", null: false
t.bigint "tag_id", null: false
t.index ["listing_id", "tag_id"], name: "index_listings_tags_on_listing_id_and_tag_id"
end
Listings Controller
class ListingsController < ApplicationController
before_action :set_listing, only: [:show, :edit, :update, :destroy]
# GET /listings
# GET /listings.json
def index
#listings = Listing.search(params[:term])
end
# GET /listings/1
# GET /listings/1.json
def show
#listing = Listing.find(params[:id])
#tags = #listing.tags
#suburb = #listing.suburb
#postcode = #suburb.post_code
end
# GET /listings/new
def new
#listing = Listing.new
end
# GET /listings/1/edit
def edit
end
# POST /listings
# POST /listings.json
def create
#listing = Listing.new(listing_params)
respond_to do |format|
if #listing.save
format.html { redirect_to #listing, notice: 'Listing was successfully created.' }
format.json { render :show, status: :created, location: #listing }
else
format.html { render :new }
format.json { render json: #listing.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /listings/1
# PATCH/PUT /listings/1.json
def update
respond_to do |format|
if #listing.update(listing_params)
format.html { redirect_to #listing, notice: 'Listing was successfully updated.' }
format.json { render :show, status: :ok, location: #listing }
else
format.html { render :edit }
format.json { render json: #listing.errors, status: :unprocessable_entity }
end
end
end
# DELETE /listings/1
# DELETE /listings/1.json
def destroy
#listing.destroy
respond_to do |format|
format.html { redirect_to listings_url, notice: 'Listing was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_listing
#listing = Listing.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def listing_params
params.require(:listing).permit(:name, :streetAddress, :telephone, :url, :term, :suburb_id, :post_code_id, :region_id, :country_id, :tag_ids)
end
end
Tags Controller
class TagsController < ApplicationController
before_action :set_tag, only: [:show, :edit, :update, :destroy]
# GET /tags
# GET /tags.json
def index
#tags = Tag.all
end
# GET /tags/1
# GET /tags/1.json
def show
#tag = Tag.find(params[:id])
#listings = #tag.listings
end
# GET /tags/new
def new
#tag = Tag.new
end
# GET /tags/1/edit
def edit
end
# POST /tags
# POST /tags.json
def create
#tag = Tag.new(tag_params)
respond_to do |format|
if #tag.save
format.html { redirect_to #tag, notice: 'Tag was successfully created.' }
format.json { render :show, status: :created, location: #tag }
else
format.html { render :new }
format.json { render json: #tag.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /tags/1
# PATCH/PUT /tags/1.json
def update
respond_to do |format|
if #tag.update(tag_params)
format.html { redirect_to #tag, notice: 'Tag was successfully updated.' }
format.json { render :show, status: :ok, location: #tag }
else
format.html { render :edit }
format.json { render json: #tag.errors, status: :unprocessable_entity }
end
end
end
# DELETE /tags/1
# DELETE /tags/1.json
def destroy
#tag.destroy
respond_to do |format|
format.html { redirect_to tags_url, notice: 'Tag was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_tag
#tag = Tag.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def tag_params
params.require(:tag).permit(:name)
end
end
Form
<%= bootstrap_form_for(#listing, local: true) do |form| %>
<%= form.text_field :name, id: :listing_name %>
<%= form.text_field :streetAddress, id: :listing_streetAddress %>
<%= form.collection_select(:suburb_id, Suburb.all, :id, :name) %>
<%= form.collection_select(:post_code_id, PostCode.all, :id, :number) %>
<%= form.collection_select(:region_id, Region.all, :id, :name) %>
<%= form.collection_select(:country_id, Country.all, :id, :name) %>
<%= form.text_field :telephone, id: :listing_telephone %>
<%= form.text_field :url, id: :listing_url %>
<%= form.select :tag_ids, Tag.all.pluck(:name, :id), {}, { multiple: true, class: "selectize" } %>
<%= form.submit %>
<% end %>
I really appreciate your help. I am sure it is probably something simple that I am doing wrong.
try this
params.require(:listing).permit(:name, :streetAddress, :telephone, :url, :term, :suburb_id, :post_code_id, :region_id, :country_id, :tag_ids => [])
source : https://github.com/rails/strong_parameters

Updating a nested record, rails will send to SQL to update the parent record id to "nil"

I have a problem in updating a nested record from its parent record update page (creation works fine).
# app/controllers/users_controller.rb
...
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to user_visites_path #user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: #user }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
...
def update
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { render :show, status: :ok, location: #user }
else
format.html { render :edit }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
...
def user_params
params.require(:user).permit(:some_attributes, profile_attributes: [:first_name, :last_name, :birthdate, :first_interview, :send_by, :sexe, :tall, :weight, :etc_attributes])
end
# app/model/profile.rb
class Profile < ActiveRecord::Base
belongs_to :user
end
# app/model/user.rb
class User < ApplicationRecord
attr_accessor :last_interview
has_one :profile
accepts_nested_attributes_for :profile
has_many :visites
end
When I do send the update request with the params:
{"some_attributes"=>"",
"profile_attributes"=>
{"first_name"=>"Jean",
"last_name"=>"Paul",
"birthdate(3i)"=>"14",
"birthdate(2i)"=>"11",
"birthdate(1i)"=>"2017",
"first_interview(3i)"=>"12",
"first_interview(2i)"=>"11",
"first_interview(1i)"=>"2017",
"send_by"=>"",
"tall"=>"",
"weight"=>"",
"etc_attributes"=>""}}
I am getting the following error from the logs:
Profile Load (0.4ms) SELECT "profiles".* FROM "profiles" WHERE "profiles"."user_id" = ? LIMIT 1 [["user_id", 414]]
SQL (2.7ms) UPDATE "profiles" SET "user_id" = ?, "updated_at" = ? WHERE "profiles"."id" = ? [["user_id", nil], ["updated_at", "2017-11-28 00:36:37.936914"], ["id", 4]]
SQLite3::ConstraintException: NOT NULL constraint failed: profiles.user_id: UPDATE "profiles" SET "user_id" = ?, "updated_at" = ? WHERE "profiles"."id" = ?
The weird part is that at the second request rails does to SQL it tries to reset "user_id" and more problematic to nil which is causing me the error.
Do you have an idea why and also, how to avoid it?

Rails 5 - has_many through and nested attributes forms

I have two models Request and TableLocation with both having a has_many through relationship joined by RequestLocation table.
I am trying to create a nested form and the table_location data is not being saved to the database.
As you can see the table_locations"=>["1"] parameter is being passed to the create action but not being saved.
Appreciate any help.
Console Output
Started POST "/requests" for 127.0.0.1 at 2017-06-07 10:35:26 -0400
Processing by RequestsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"mHV/xbmdfHmCAsi16KXlW+0bWVSkEo9SRVchdyPpL60o3m3SuKEt4nuUT4PJNEyCsWq3Nj4IWiCMlDbhiPewdA==", "request"=>{"concierge_name"=>"Alex", "concierge_number"=>"954-123-4567", "concierge_email"=>"alex#email.com", "client_name"=>"Adam", "client_number"=>"954-765-4321", "client_email"=>"adam#email.com", "hotel_employee"=>"0", "concierge_service"=>"0", "vip_promoter"=>"0", "arriving_with_client"=>"1", "client_alone"=>"0", "males"=>"", "females"=>"1", "table_minimum"=>"1000", "arrival_time(1i)"=>"2017", "arrival_time(2i)"=>"6", "arrival_time(3i)"=>"7", "arrival_time(4i)"=>"14", "arrival_time(5i)"=>"35", "table_locations"=>["1"], "comments"=>""}, "commit"=>"Submit"}
(0.1ms) BEGIN
SQL (0.4ms) INSERT INTO "requests" ("concierge_name", "concierge_number", "concierge_email", "client_name", "client_number", "client_email", "arriving_with_client", "people", "females", "table_minimum", "arrival_time", "comments", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) RETURNING "id" [["concierge_name", "Alex"], ["concierge_number", "954-123-4567"], ["concierge_email", "alex#email.com"], ["client_name", "Adam"], ["client_number", "954-765-4321"], ["client_email", "adam#email.com"], ["arriving_with_client", "t"], ["people", 1], ["females", 1], ["table_minimum", 1000], ["arrival_time", "2017-06-07 14:35:00"], ["comments", ""], ["created_at", "2017-06-07 14:35:26.658718"], ["updated_at", "2017-06-07 14:35:26.658718"]]
(0.3ms) COMMIT
Redirected to http://localhost:3000/thanks
Completed 302 Found in 8ms (ActiveRecord: 0.8ms)
app/models/request.rb
class Request < ApplicationRecord
has_many :request_locations
has_many :table_locations, through: :request_locations
end
app/models/table_locations.rb
class TableLocation < ApplicationRecord
has_many :request_locations
has_many :requests, through: :request_locations
end
app/models/request_location.rb
class RequestLocation < ApplicationRecord
belongs_to :request
belongs_to :table_location
end
app/controllers/requests_controller.rb
class RequestsController < ApplicationController
before_action :set_request, only: [:show,
:edit,
:update,
:destroy]
before_action :authenticate_admin!, except: [:index,
:new,
:create]
def index
redirect_to root_path unless admin_signed_in?
#requests = Request.search(params[:term], params[:filter], params[:page])
end
def show
end
def new
#request = Request.new
end
def edit
end
def create
#request = Request.new(request_params)
#request.people = (#request.males || 0) + (#request.females || 0)
respond_to do |format|
if #request.save
format.html { redirect_to thanks_path, notice: 'Request was successfully created.' }
format.json { render :show, status: :created, location: #request }
else
format.html { render :new }
format.json { render json: #request.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #request.update(request_params)
format.html { redirect_to #request, notice: 'Request was successfully updated.' }
format.json { render :show, status: :ok, location: #request }
else
format.html { render :edit }
format.json { render json: #request.errors, status: :unprocessable_entity }
end
end
end
def destroy
#request.destroy
respond_to do |format|
format.html { redirect_to requests_url, notice: 'Request was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_request
#request = Request.find(params[:id])
end
def request_params
params.require(:request).permit(:concierge_name,
:concierge_number,
:concierge_email,
:client_name,
:client_number,
:client_email,
:hotel_employee,
:concierge_service,
:vip_promoter,
:arriving_with_client,
:client_alone,
:people,
:males,
:females,
:table_minimum,
:arrival_time,
:comments,
table_locations: [:id]
)
end
end
app/views/requests/_form.html.erb
...
<% TableLocation.all.each do |t| %>
<%= check_box_tag "request[table_locations][]", t.id, #request.table_locations.include?(t.id) %>
<%= t.location %>
<br />
<% end %>
...
Explanations:
Your request_params permits table_locations: [:id], but this only permits the following format:
Parameters: {"utf8"=>"✓", ... "request"=>{"table_locations"=>{"id"=>"1"}, "comments"=>""}, "commit"=>"Submit"}
but yours is showing to be:
Parameters: {"utf8"=>"✓", ... "request"=>{"table_locations"=>["1"], "comments"=>""}, "commit"=>"Submit"}
therefore, try this: puts request_params inside the create method, and you'll notice that it doesn't have table_locations values (even though you thought it's there, but it's not), because it is not "properly" whitelisted in your strong params request_params.
To be able to associate multiple TableLocations objects to a newly built Request object, the format should be something like below
request = Request.new(table_location_ids: [1,2,3,4,5])
but from your implementation, you're doing it like this (which won't work):
request = Request.new(table_locations: [1,2,3,4,5])
# => this will raise an error:
# ActiveRecord::AssociationTypeMismatch: TableLocation expected, got Fixnum
# however yours didn't raise an error, because it was not whitelisted in the request_params in the first place
Solution:
requests_controller.rb
def request_params
params.require(:request).permit(..., table_location_ids: [])
end
_form.html.erb
<% TableLocation.all.each do |t| %>
<%= check_box_tag "request[table_location_ids][]", t.id %>
<%= t.location %>
<br />
<% end %>
Recommendation:
just in case you don't know yet that you can do the following in this way, I'll be refactoring your code to look something like this:
requests_controller.rb
def create
#table_locations = TableLocation.all
end
_form.html.erb
<%= form_for #request do |f| %>
<% #table_locations.each do |table_location| %>
<%= f.check_box :table_location_ids, multiple: true, table_location.id %>
<% end %>
<% end %>

Rails4 Association autosave does not work

I am new in Rails.
I have a model association (belongs_to -> has_many), but the application does not save the associated model's id in the foreign key column.
The migration file:
class CreatePartnerAdvertisements < ActiveRecord::Migration
def change
create_table :partner_advertisements do |t|
t.belongs_to :user, index: true
t.belongs_to :county, index: true
t.text :description, null: true
t.string :city, null: true, limit: 100
t.integer :age, null: false, limit: 120
t.integer :height, null: true, limit: 300
t.integer :weight, null: true, limit: 300
t.timestamps null: false
t.timestamps null: false
end
end
end
The model which foreign key's column always 1 after saves
class PartnerAdvertisement < ActiveRecord::Base
belongs_to :user, autosave: true
belongs_to :county, autosave: true
validates_associated :county
end
This is the view
<%= form_for(#partner_advertisement) do |f| %>
<div class="field">
<%= f.label :county %><br />
<%= collection_select :partner_advertisement ,:county_id, County.all, :id, :name, {selected: #partner_advertisement.county_id} %>
</div>
<% end %>
So here, I select a county from the list, but when the parter_advertisement saved, the county_id not modified... same with the user_id...
So it seems in Rails the association saving does not work. Of course I can manually save the foreign key ids if in the controller I get the right parameter from the request.
But for me it will great, if the ActiveRecord could automatically save the foreign keys for partner_advertisement.
The controller:
class PartnerAdvertisementsController < ApplicationController
before_action :authenticate_user!
before_action :set_partner_advertisement, only: [:show, :edit, :update, :destroy]
# GET /partner_advertisements
# GET /partner_advertisements.json
def index
#partner_advertisements = PartnerAdvertisement.where(is_active: true)
end
# GET /partner_advertisements/1
# GET /partner_advertisements/1.json
def show
end
# GET /partner_advertisements/new
def new
#partner_advertisement = PartnerAdvertisement.new
end
# GET /partner_advertisements/1/edit
def edit
end
# POST /partner_advertisements
# POST /partner_advertisements.json
def create
#partner_advertisement = PartnerAdvertisement.new(partner_advertisement_params)
##partner_advertisement.user_id = current_user.id
respond_to do |format|
if #partner_advertisement.save
format.html { redirect_to #partner_advertisement, notice: 'Partner advertisement was successfully created.' }
format.json { render :show, status: :created, location: #partner_advertisement }
else
format.html { render :new }
format.json { render json: #partner_advertisement.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /partner_advertisements/1
# PATCH/PUT /partner_advertisements/1.json
def update
respond_to do |format|
if #partner_advertisement.update(partner_advertisement_params)
format.html { redirect_to #partner_advertisement, notice: 'Partner advertisement was successfully updated.' }
format.json { render :show, status: :ok, location: #partner_advertisement }
else
format.html { render :edit }
format.json { render json: #partner_advertisement.errors, status: :unprocessable_entity }
end
end
end
# DELETE /partner_advertisements/1
# DELETE /partner_advertisements/1.json
def destroy
#partner_advertisement.destroy
respond_to do |format|
format.html { redirect_to partner_advertisements_url, notice: 'Partner advertisement was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_partner_advertisement
#partner_advertisement = PartnerAdvertisement.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def partner_advertisement_params
#params[:partner_advertisement]
params.require(:partner_advertisement).permit(:age, :height, :weight, :city, :county, :description, :style, :club, :level, :goal, :weekly, :occasionally, :years, :is_active)
end
end
The update request's log without any errors:
Started PATCH "/partner_advertisements/1" for 10.0.2.2 at 2015-10-11 20:01:06 +0000
Cannot render console from 10.0.2.2! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by PartnerAdvertisementsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"dVNIi2H59EuZFrlrE+1ujRzDauJdc4Kkox6TbWNzpGK1mOoyfk6U8s9B/+HzASofd7DLe8/kdn4UKKIPCepjog==", "partner_advertisement"=>{"description"=>"yeap yeapr", "city"=>"Eger", "county_id"=>"9", "age"=>"45", "height"=>"43", "weight"=>"435", "style"=>"asdfdsafdf", "club"=>"adsfdf", "level"=>"asdfdsf", "goal"=>"sdfdsf", "weekly"=>"4", "occasionally"=>"3", "years"=>"3", "is_active"=>"1"}, "commit"=>"Update Partner advertisement", "id"=>"1"}
[1m[35mUser Load (1.6ms)[0m SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1 [["id", 1]]
[1m[36mPartnerAdvertisement Load (1.6ms)[0m [1mSELECT "partner_advertisements".* FROM "partner_advertisements" WHERE "partner_advertisements"."id" = ? LIMIT 1[0m [["id", 1]]
Unpermitted parameter: county_id
[1m[35m (0.1ms)[0m begin transaction
[1m[36m (0.2ms)[0m [1mcommit transaction[0m
Redirected to http://localhost:3000/partner_advertisements/1
Completed 302 Found in 15ms (ActiveRecord: 3.6ms)
So you can see the county_id is 9 in the request, but in the database always 1 after save... :(
You need to allow the county_id in your partner_advertisement_params.
Just add it like:
def partner_advertisement_params
#params[:partner_advertisement]
params.require(:partner_advertisement).permit(:age, :height, :weight, :city, :county, :description, :style, :club, :level, :goal, :weekly, :occasionally, :years, :is_active, :county_id)
end

Rails Association Bug

I am getting NoMethodError in SitesController#index undefined method `name' for nil:NilClass in my Salesman index view and cannot find the culprit.
I have a simple rails app with the following tables: Customer, Salesman and Invoice.
In the index view for the customer table I have the following call:
<% #customers.each do |customer| %>
<%= customer.name %></td>
<%= customer.address %>
<%= customer.salesman.name %>
<% end %>
This is the call that results in the undefined method ´name´ listed above. I made sure the salesman table has a salesman_id foreign key in the customer table. Also, I made the respective association in the models:
class Customer < ActiveRecord::Base
belongs_to :salesman
has_many :invoices
end
class Salesman < ActiveRecord::Base
has_many :customers
end
I tested the customer.salesman.name call in the console and it works flawlessly. The show view for the customer has an exact call like this one and it also works. The only way I can make the customer index pass is by replacing customer.salesman.name to customer.salesman_id returning only the id.
Thank you for your time here.
***schema.rb***
ActiveRecord::Schema.define(version: 20150325172212) do
create_table "customers", force: :cascade do |t|
t.string "name"
t.string "address"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "salesman_id"
end
create_table "invoices", force: :cascade do |t|
t.datetime "date"
t.string "fid"
t.integer "salesman_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "address"
end
create_table "salesmen", force: :cascade do |t|
t.datetime "name"
t.string "address""
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
***controllers***
**customer**
Class CustomersController < ApplicationController
before_action :set_customer, only: [:show, :edit, :update, :destroy]
# GET /customers
# GET /customers.json
def index
#customers = Customer.all
end
# GET /customers/1
# GET /customers/1.json
def show
end
# GET /customers/new
def new
#customer = Customer.new
end
# GET /customers/1/edit
def edit
end
# POST /customers
# POST /customers.json
def create
#customer = Customer.new(customer_params)
respond_to do |format|
if #customer.save
format.html { redirect_to #customer, notice: 'Customer was successfully created.' }
format.json { render :show, status: :created, location: #customer }
else
format.html { render :new }
format.json { render json: #customer.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /customers/1
# PATCH/PUT /customers/1.json
def update
respond_to do |format|
if #customer.update(customer_params)
format.html { redirect_to #customer, notice: 'Customer was successfully updated.' }
format.json { render :show, status: :ok, location: #customer }
else
format.html { render :edit }
format.json { render json: #customer.errors, status: :unprocessable_entity }
end
end
end
# DELETE /customers/1
# DELETE /customers/1.json
def destroy
#customer.destroy
respond_to do |format|
format.html { redirect_to customers_url, notice: 'Customer was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_cliente
#cliente = Cliente.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def customer_params
params.require(:customer).permit(:name, :address, :salesman_id)
end
end
***salesman***
class SalesmenController < ApplicationController
before_action :set_salesman, only: [:show, :edit, :update, :destroy]
# GET /salesmans
# GET /salesmans.json
def index
#salesmen = Salesman.all
end
# GET /salesmans/1
# GET /salesmans/1.json
def show
end
# GET /salesmans/new
def new
#salesman = Salesman.new
end
# GET /salesmans/1/edit
def edit
end
# POST /salesmans
# POST /salesmans.json
def create
#salesman = Salesman.new(salesman_params)
respond_to do |format|
if #salesman.save
format.html { redirect_to #salesman, notice: 'Salesman was successfully created.' }
format.json { render :show, status: :created, location: #salesman }
else
format.html { render :new }
format.json { render json: #salesman.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /salesmans/1
# PATCH/PUT /salesmans/1.json
def update
respond_to do |format|
if #salesman.update(salesman_params)
format.html { redirect_to #salesman, notice: 'Salesman was successfully updated.' }
format.json { render :show, status: :ok, location: #salesman }
else
format.html { render :edit }
format.json { render json: #salesman.errors, status: :unprocessable_entity }
end
end
end
# DELETE /salesmans/1
# DELETE /salesmans/1.json
def destroy
#salesman.destroy
respond_to do |format|
format.html { redirect_to salesmans_url, notice: 'Salesman was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_salesman
#salesman = Salesman.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def salesman_params
params.require(:salesman).permit(:name, :address)
end
**invoice**
class InvoicesController < ApplicationController
before_action :set_invoice, only: [:show, :edit, :update, :destroy]
# GET /invoices
# GET /invoices.json
def index
#invoices = Invoice.all
end
# GET /invoices/1
# GET /invoices/1.json
def show
#invoice = Invoice.find(params[:id])
#ordenes = #invoice.ordenes
end
# GET /invoices/new
def new
#invoice = Invoice.new
end
# GET /invoices/1/edit
def edit
end
# POST /invoices
# POST /invoices.json
def create
#invoice = Invoice.new(invoice_params)
respond_to do |format|
if #invoice.save
format.html { redirect_to #invoice, notice: 'Invoice was successfully created.' }
format.json { render :show, status: :created, location: #invoice }
else
format.html { render :new }
format.json { render json: #invoice.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /invoices/1
# PATCH/PUT /invoices/1.json
def update
respond_to do |format|
if #invoice.update(invoice_params)
format.html { redirect_to #invoice, notice: 'Invoice was successfully updated.' }
format.json { render :show, status: :ok, location: #invoice }
else
format.html { render :edit }
format.json { render json: #invoice.errors, status: :unprocessable_entity }
end
end
end
# DELETE /invoices/1
# DELETE /invoices/1.json
def destroy
#invoice.destroy
respond_to do |format|
format.html { redirect_to invoices_url, notice: 'Invoice was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_invoice
#invoice = Invoice.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def invoice_params
params.require(:invoice).permit(:date, :fid, :name, :address, :salesman_id)
end
end
-davefogo
Add the following to your views instead of what you currently have<%= customer.salesman.name if customer.salesman %>
This will ensure that you're not calling name when customer doesn't have a salesman.
Try this:
<% #customers.each do |customer| %>
<%= customer.name %>
<%= customer.address %>
<%= customer.salesman.try(:name) %>
<% end %>
Do this:
<% #customers.each do |customer| %>
<% Rails.logger.debug "\n\n#{#customers} has a nil customer in it\n\n" if customer.nil? %>
<% Rails.logger.debug "\n\nCustomer #{customer.id} has no salesman for [#{customer.salesman_id}]\n\n" if customer.salesman.nil? %>
<%= customer.name %>
<%= customer.address %>
<%= customer.salesman.name %>
<% end %>
...and then check your logs after hitting the index.

Resources