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
Related
I'm getting a missing attribute error when trying to automatically create a InvoiceAppCollection when an Invoice is created.
This is the error that I'm getting:
ActiveModel::MissingAttributeError in InvoicesController#create
can't write unknown attribute app_collection_id
From what I've looked up when other people have this issue it has to do with the relationships between the models, but I'm pretty sure that I have the models communicating to each other properly.
The function I wrote to create the invoice app collection is in the invoice controller
def create_invoice_app_collection
InvoiceAppCollection.create(
po_number: #invoice.po_number,
app_collection: #invoice.app_collection
)
end
Here are my models and controllers. I also have the select box where the app_collections are being selected at the bottom.
Here are the Models
class AppCollection < ApplicationRecord
belongs_to :company
acts_as_tenant(:company)
has_many :invoice_app_collections
has_many :invoices, through: :invoice_app_collections
validates :name, uniqueness: true
end
class Invoice < ApplicationRecord
belongs_to :company
acts_as_tenant(:company)
has_many :invoice_app_collections
has_many :app_collections, through: :invoice_app_collections
validates :expiration, on: [:create, :update, :save], :presence => true
end
class InvoiceAppCollection < ApplicationRecord
belongs_to :app_collection
belongs_to :invoice
belongs_to :company
acts_as_tenant(:company)
accepts_nested_attributes_for :app_collection
end
AppCollectionController
class AppCollectionsController < ApplicationController
before_action :set_app_collection, only: %i[ show edit update destroy ]
def index
AppCollections = app_collection.all
end
def create
#app_collection = app_collection.new(app_collection_params)
respond_to do |format|
if #app_collection.save
format.html { redirect_to app_collection_url(#app_collection), notice: "App collection was successfully created." }
format.json { render :show, status: :created, location: #app_collection }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #app_collection.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #app_collection.update(app_collection_params)
format.html { redirect_to app_collection_url(#app_collection), notice: "App collection was successfully updated." }
format.json { render :show, status: :ok, location: #app_collection }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #app_collection.errors, status: :unprocessable_entity }
end
end
end
def destroy
#app_collection.destroy
respond_to do |format|
format.html { redirect_to app_collections_url, notice: "app collection was successfully destroyed." }
format.json { head :no_content }
end
end
private
def set_app_collection
#app_collection = app_collection.find(params[:id])
end
def app_collection_params
params.require(:app_collection).permit(:app_collection_type_id, :name, :company_id)
end
end
InvoicesController
class InvoicesController < ApplicationController
before_action :set_invoice, only: %i[ show edit update destroy ]
prepend_before_action :set_tenant
after_action :create_invoice_app_collection, only: [:create, :update]
def new
#invoice_app_collection = Invoice.new
end
def create
#invoice = Invoice.new(invoice_params)
respond_to do |format|
if #invoice.save
format.html { redirect_to invoice_url(#invoice), notice: "Invoice was successfully created." }
format.json { render :show, status: :created, location: #invoice }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #invoice.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #invoice.update(invoice_params)
format.html { redirect_to invoice_url(#invoice), notice: "Invoice was successfully updated." }
format.json { render :show, status: :ok, location: #invoice }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #invoice.errors, status: :unprocessable_entity }
end
end
end
private
def set_invoice
#invoice = Invoice.find(params[:id])
end
def invoice_params
params.require(:invoice).permit(:company_id, :po_number, :amount, :expiration, {:app_collection_id => []} )
end
def create_invoice_app_collection
InvoiceAppCollection.create(
po_number: #invoice.po_number,
app_collection: #invoice.app_collection
)
end
end
InvoiceAppCollectionsController
class InvoiceAppCollectionsController < ApplicationController
before_action :set_invoice_app_collection, only: %i[ show edit update destroy ]
prepend_before_action :set_tenant
def new
#invoice_app_collection = InvoiceAppCollection.new
end
private
def set_invoice_app_collection
#invoice_app_collection = InvoiceAppCollection.find(params[:id])
end
def invoice_app_collection_params
params.require(:invoice_app_collection).permit(:company_id, :po_number, {:app_collection => []} )
end
end
App Collection being set in the invoice form
<div>
<%= form.label :app_collection, style: "display: block" %>
<label> Select multiple app collections by holding the command key </label>
<%= form.select :app_collection, options_for_select(app_collection.all.map {|a| [a.name, a.name]}),{include_blank: false} , class:"form-select", multiple: true %>
</div>
Schema
create_table "app_collections", charset: "latin1", force: :cascade do |t|
t.integer "app_collection_type_id"
t.string "name"
t.integer "company_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "invoice_app_collections", charset: "latin1", force: :cascade do |t|
t.integer "company_id"
t.string "po_number"
t.string "app_collection"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "invoices", charset: "latin1", force: :cascade do |t|
t.integer "company_id"
t.string "po_number"
t.decimal "amount", precision: 10
t.datetime "expiration"
t.string "app_collection"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
I believe that the issue is that the app_collection is an array that gets sent to InvoiceAppController so I set it to an array in both controllers and that hasn't fixed it. I also allowed InvoiceAppCollection to accept nested attribues for app_collection but that also isn't fixing it.
I'm not really sure how to resolve this error so any guidance would be very appreciated
Thank you!
I found a small problem, you wrote: #invoice.app_collection, but as your Invoice model is:
class Invoice < ApplicationRecord
has_many :app_collections, through: :invoice_app_collections
end
The code will look for relation belongs_to :app_collection, it required column app_collection_id in your Invoice model, which is not correct in this many-to-many between Invoice and AppCollection. Btw, I think this part {:app_collection_id => []} of invoice_params could raise error when this code Invoice.new(invoice_params) is executed
My suggestion, to update the many-to-many relation:
#invoice.app_collections = AppCollection.where(id: params[:app_collection_ids]) // maybe you will want to update the params structure
#invoice.save
This code will auto-generate correspondant InvoiceAppCollection records.
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
I am setting up a relationship between two of my models. A Patient Model and Worklist Model. My patient can belong to a worklist and a worklist can have many patients. In my form for patients I want to be able to select the worklist from a dropdown menu. I created a method in the form but its throwing an error. Here is my code:
from _form.html.erb:
<div class="field">
<%= f.label :worklist_id %>
<%= f.collection_select :worklist_id, #worklists, :id , :name %>
</div>
from patient.rb:
class Patient < ActiveRecord::Base
belongs_to :worklist
end
from worklist.rb
class Worklist < ActiveRecord::Base
has_many :patients
end
from schema.rb
create_table "patients", force: :cascade do |t|
t.string "lastname"
t.string "middlename"
t.string "firstname"
t.date "birthdate"
t.string "sex"
t.string "ethnicity"
t.string "uniqueid"
t.string "accountnumber"
t.string "medicaidid"
t.string "medicareid"
t.string "ssn"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "worklist_id"
end
And this is the error I am getting:
NoMethodError in Patients#edit
undefined method `worklist_select'
Here is the PatientController:
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
# POST /patients
# POST /patients.json
def create
#patient = Patient.new(patient_params)
#worklists = Worklist.all
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
# GET /patients/1/edit
def edit
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
def import
Patient.import(params[:file])
redirect_to patients_path, notice: "Patients Added Successfully"
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(:lastname, :middlename, :firstname, :birthdate, :sex, :ethnicity, :uniqueid, :accountnumber, :medicaidid, :medicareid, :ssn, :worklist_id)
end
end
Worklist.all in the view is a problem. The view talking to the db directly is never good. That is the Controller's (or a Service's) job.
In your controller, you would want something like: #worklists = Worklist.all, then use #worklists in the view.
This is just a start though. Can you post your controller so we can help further?
UPDATE: Now we have a better idea of where this is going. Lets do this:
So in your PatientsController, you would want this in your create method:
#worklists = Worklist.all
Then in your _form.html.erb (from the patient folder NOT the Worklist folder), you would want:
<%= f.label :worklist_id %>
<%= f.collection_select :worklist_id, #worklists, :id , :name %>
I think if you just change this:
<%= worklist_select( :patient, :worklist_id, Worklist.all, :id, :name, {}, { :multiple => false } ) %>
To something more like this:
<%= f.select( :worklist_id, Worklist.all, :id, :name, {}, { :multiple => false } ) %>
You might get what you want.
Good day, community.
First of all, I'm a newbie in Rails. I did some thing with it in College 4 years ago, and now I decided to get back on it. Lots of things changed in version 4.
Anyway, I am experiencing issues with strong parameters. Here's what I have:
I'm using Ruby 2.1, Rails 4.1.
I am trying to create a form for a hockey match with parameters (id, team_a, team_b, arena, date, score_a, score_b). team is a table (id, name) and arena is a table (id, name).
When I pass the parameters from form to the controller, the json parameters seem to be okay. But, when it is converted into match_params it is missing some values from parameters from other table. For example, I am passing arena_id: 12, but it shows arena_id: as blank.
I've spent over 5 days on this thing. Any help appreciated.
Some of the code is bellow. Let me know if you need me to provide more information...
migration data
class CreateMatches < ActiveRecord::Migration
def change
create_table :matches do |t|
t.references :team_a, default: 1 # unknown
t.references :team_b, default: 1 # unknown
t.references :arena, default: 1 # unknown
t.datetime :date
t.integer :score_a
t.integer :score_b
t.timestamps
end
add_index :matches, :team_a_id
add_index :matches, :team_b_id
add_index :matches, :arena_id
end
end
class CreateTeams < ActiveRecord::Migration
def change
create_table :teams do |t|
t.string :name, null: false
t.timestamps
end
end
end
class CreateArena < ActiveRecord::Migration
def change
create_table :arena do |t|
t.string :name, null: false
t.timestamps
end
end
end
match.rb (model)
class Match < ActiveRecord::Base
belongs_to :team_a, :class_name => 'Team'
belongs_to :team_b, :class_name => 'Team'
belongs_to :arena
end
team.rb (model)
class Team < ActiveRecord::Base
has_many :matches
accepts_nested_attributes_for :matches
end
arena.rb (model)
class Arena < ActiveRecord::Base
has_many :matches
accepts_nested_attributes_for :matches
end
matches_controller.rb
class MatchesController < ApplicationController
before_action :set_match, only: [:show, :edit, :score, :update, :destroy]
include ActionView::Helpers::DateHelper
def index
# some code
end
def show
# some code
end
def new
#match = Match.new
#teams = Team.all.order("name ASC")
#arenas = Arena.all.order("name ASC")
end
# GET /matches/1/edit
def edit
# some code
end
def create
puts YAML::dump(match_params) # Checking passed params. Output is bellow
#match = Match.new(match_params)
respond_to do |format|
if #match.save
format.html { redirect_to #match, notice: 'Match was successfully created.' }
format.json { render action: 'show', status: :created, location: #match }
else
format.html { render action: 'new' }
format.json { render json: #match.errors, status: :unprocessable_entity }
end
end
end
def update
end
def destroy
end
private
# Use callbacks to share common setup or constraints between actions.
def set_match
#match = Match.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def match_params
params.require(:match).permit(:date, :score_a, :score_b, team_a_id: [:id, :name], team_b_id: [:id, :name], arena_id: [:id, :name])
end
public
end
teams_controller.rb
class TeamsController < ApplicationController
before_action :set_team, only: [:show, :edit, :update, :destroy]
layout :false
def index
#teams = Team.all
end
def show
end
def new
#team = Team.new
end
def edit
end
def create
#team = Team.new(team_params)
respond_to do |format|
if #team.save
format.json { render action: 'show', status: :created, location: #team }
format.html { redirect_to #team, notice: 'Team was successfully created.' }
else
format.html { render action: 'new' }
format.json { render json: #team.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #team.update(team_params)
format.json { head :no_content }
format.html { redirect_to #team, notice: 'Team was successfully updated.' }
else
format.html { render action: 'edit' }
format.json { render json: #team.errors, status: :unprocessable_entity }
end
end
end
def destroy
#team.destroy
respond_to do |format|
format.html { redirect_to teams_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_team
#team = Team.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def team_params
params.require(:team).permit(:name)
end
end
arenas_controller.rb
class ArenasController < ApplicationController
before_action :set_arena, only: [:show, :edit, :update, :destroy]
layout false
def index
#arena = Arena.all
end
def show
end
def new
#arena = Arena.new
end
def edit
end
def create
#arena = Arena.new(arena_params)
respond_to do |format|
if #arena.save
format.json { render action: 'show', status: :created, location: #arena }
format.html { redirect_to #arena, notice: 'Arena was successfully created.' }
else
format.html { render action: 'new' }
format.json { render json: #arena.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #arena.update(arena_params)
format.json { head :no_content }
format.html { redirect_to #arena, notice: 'Arena was successfully updated.' }
else
format.html { render action: 'edit' }
format.json { render json: #arena.errors, status: :unprocessable_entity }
end
end
end
def destroy
#arena.destroy
respond_to do |format|
format.html { redirect_to arenas_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_arena
#arena = Arena.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def arena_params
params.require(:arena).permit(:name)
end
end
matches/_match.html.erb
<%= form_for(#match, html: {role: 'form', class: 'form-horizontal'}) do |f| %>
<% if #match.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#match.errors.count, "error") %> prohibited this match from being saved:</h2>
<ul>
<% #match.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.label 'Home Team' %>
<%= f.collection_select :team_a_id, #teams, :id, :name, {prompt: true}, {class: ''} %>
<%= f.label 'Visitor Team' %>
<%= f.collection_select :team_b_id, #teams, :id, :name, {prompt: true}, {class: ''} %>
<%= f.label 'Arena' %>
<%= f.collection_select :arena_id, #arenas, :id, :name, {prompt: true}, {class: ''} %>
<%= f.label 'Date' %>
<%= f.datetime_select :date, class: 'form-control' %>
<%= f.submit value: 'Submit' %>
<% end %>
And here's what I am getting in console after dumping data:
Started POST "/matches" for 127.0.0.1 at 2014-05-06 18:24:20 -0700
Processing by MatchesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"0RJjnpczVkp2unG9VITyHYC89ThgELn5kVE2wYRymBU=", "match"=>{"team_a_id"=>"24", "team_b_id"=>"27", "arena_id"=>"21", "date(1i)"=>"2014", "date(2i)"=>"5", "date(3i)"=>"6", "date(4i)"=>"18", "date(5i)"=>"24"}, "commit"=>"Update"}
User Load (0.5ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 ORDER BY `users`.`id` ASC LIMIT 1
--- !ruby/hash:ActionController::Parameters
date(1i): '2014'
date(2i): '5'
date(3i): '6'
date(4i): '18'
date(5i): '24'
team_a_id:
team_b_id:
arena_id:
(0.2ms) BEGIN
SQL (1.5ms) INSERT INTO `matches` (`created_at`, `date`, `arena_id`, `team_a_id`, `team_b_id`, `updated_at`) VALUES ('2014-05-07 01:24:20', '2014-05-07 01:24:00', NULL, NULL, NULL, '2014-05-07 01:24:20')
(0.2ms) COMMIT
Redirected to http://localhost:3000/matches/90
Completed 302 Found in 13ms (ActiveRecord: 2.4ms)
Take a look at your match_params, and compare it to what parameters are being passed to your controller from your form.
def match_params
params.require(:match).permit(:date, :score_a, :score_b, team_a_id: [:id, :name], team_b_id: [:id, :name], area_id: [:id, :name])
end
Parameters: {"utf8"=>"✓", "authenticity_token"=>"0RJjnpczVkp2unG9VITyHYC89ThgELn5kVE2wYRymBU=", "match"=>{"team_a_id"=>"24", "team_b_id"=>"27", "arena_id"=>"21", "date(1i)"=>"2014", "date(2i)"=>"5", "date(3i)"=>"6", "date(4i)"=>"18", "date(5i)"=>"24"}, "commit"=>"Update"}
You're permitting your arena_id in match_params as an array called area_id, with elements :id and :name. However, it's being passed from your form as just arena_id. You should change your match_params function to:
def match_params
params.require(:match).permit(:date, :score_a, :score_b, :team_a_id, :team_b_id, :arena_id)
end
Note that I've also changed :team_a_id and :team_b_id to be consistent with what's being passed in your parameters too, although it doesn't look like you're passing :score_a or :score_b. You should check out strong parameters in the rails guides for more information.
Okay, I found my mistake. (Thanks to JKen13579)
I have put params in the wrong place.
It should be something like that:
def match_params
params.require(:match).permit(:date, :score_a, :score_b, :team_a_id, :team_b_id , :arena_id)
end
def team_params
params.require(:team).permit(:name, matches_params:[:id, :match_id, :name])
end
def arena_params
params.require(:arena).permit(:name, matches_params:[:id, :match_id, :name])
end
It fixed the issue.
everyting but name will be removed when you call this:
params.require(:arena).permit(:name)
I'm having "ForbiddenAttributesError" in my Rails 4 application. What am I missing here?
Also the problem is, why "examination_id" parameter isn't sent to the request?
Request
Started POST "/examinations/1/participations" for 127.0.0.1 at 2014-03-26 10:47:01 +0200
Processing by ParticipationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"EuGZIXKJE9a1It6Ema5t+g07vXngQoqPMV5qQBfekfg=", "participation"=>{"user_id"=>"1", "examination_id"=>"", "language_preference"=>"İngilizce", "exam_center_preference"=>"1", "disability"=>"0"}, "commit"=>"Sınava Başvur", "examination_id"=>"1"}
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1
Examination Load (0.2ms) SELECT "examinations".* FROM "examinations" WHERE "examinations"."id" = ? LIMIT 1 [["id", "1"]]
Completed 500 Internal Server Error in 5ms
ActiveModel::ForbiddenAttributesError (ActiveModel::ForbiddenAttributesError):
app/controllers/participations_controller.rb:37:in `create'
Routes.rb
resources :examinations do
resources :participations
end
Participation.rb
class Participation < ActiveRecord::Base
belongs_to :user
belongs_to :examination
end
Examination.rb
class Examination < ActiveRecord::Base
has_many :participations
has_many :users, :through => :participations
has_many :exam_fees, dependent: :destroy
has_many :exam_languages, dependent: :destroy
end
participations_controller.rb
#encoding: utf-8
class ParticipationsController < ApplicationController
before_filter :authenticate_user!
before_action :set_participation, only: [:show, :edit, :update, :destroy]
before_filter :get_examination
def get_examination
#examination = Examination.find(params[:examination_id])
end
# GET /participations
# GET /participations.json
def index
#participations = #examination.participations
end
# GET /participations/1
# GET /participations/1.json
def show
#participation = #examination.participations.find(params[:id])
end
# GET /participations/new
def new
#participation = Participation.new
end
# GET /participations/1/edit
def edit
end
# POST /participations
# POST /participations.json
def create
#participation = #examination.participations.new(params[:participation])
#participation.user = current_user
respond_to do |format|
if #participation.save
redirect_to #examination
format.html { redirect_to [#examination, #participation], notice: 'Sınav Katılımınız Oluşturuldu!' }
format.json { render action: 'show', status: :created, location: [#examination, #participation] }
else
render 'new'
format.html { render action: 'new' }
format.json { render json: #participation.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /participations/1
# PATCH/PUT /participations/1.json
def update
respond_to do |format|
if #participation.update(participation_params)
format.html { redirect_to [#examination, #participation], notice: 'Sınav Katılımını Güncellendi!' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #participation.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_participation
#participation = Participation.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def participation_params
params.require(:participation).permit(:user_id, :examination_id, :payment_status, :language_preference, :exam_center_preference, :disability)
end
end
/views/participations/_form.html.erb
<%= simple_form_for([#examination, #participation]) do |f| %>
<%= f.error_notification %>
<fieldset>
<legend>Sınav Katılımı</legend>
<%= f.input :user_id, :as => :hidden, :input_html => { :value => current_user.id } %>
<%= f.input :examination_id, as: :hidden %>
<%= f.input :language_preference, collection: ["Türkçe", "İngilizce", "Rusça"], label: 'Sınav Dili Tercihi' %>
<%= f.input :exam_center_preference, collection:ExamCenter.all, label_method: :city, as: :select, label: 'Sınav Merkezi Tercihi' %>
<%= f.input :disability, inline_label: 'Yardımcı İstiyorum', label: false %>
<%= f.button :submit, "Sınava Başvur" %>
</fieldset>
<% end %>
In order to assign parameters in Rails 4 to object, you should use strong parameters 'syntax' implemented in your participation_params method, instead of passing params directly. So change line:
#participation = #examination.participations.new(params[:participation])
to:
#participation = #examination.participations.new(participation_params)
Since you create your Participation record through association, you don't really need examination_id param in this controller. What's more, if you allow this parameter, it becomes easy to assign Participation to Examination other than from which context you create Participation, which I doubt to be desirable. So I guess you should remove examination_id both from fields in your form and from participation_params method.