HABTM avoid dupe in join table - ruby-on-rails

I've read this question : has_and_belongs_to_many, avoiding dupes in the join table but I wasn't able to fix my issue;
I've got a class TypeProduit which has many ExtensionFichier :
class TypeProduit < ActiveRecord::Base
has_and_belongs_to_many :extension_fichiers
end
and:
class ExtensionFichier < ActiveRecord::Base
has_and_belongs_to_many :type_produits
end
They are related thanks to
class LinkExtensionFichiers < ActiveRecord::Migration
def change
create_join_table :extension_fichiers, :type_produits
end
end
Edit:
Here's the [correct] Controler:
class TypeProduitsController < ApplicationController
before_action :set_type_produit, only: [:show, :edit, :update, :destroy]
# GET /type_produits
# GET /type_produits.json
def index
#type_produits = TypeProduit.all
end
# GET /type_produits/1
# GET /type_produits/1.json
def show
end
# GET /type_produits/new
def new
#type_produit = TypeProduit.new
end
# GET /type_produits/1/edit
def edit
end
# POST /type_produits
# POST /type_produits.json
def create
#type_produit = TypeProduit.new(type_produit_params)
puts "------extension_fichier_params------"
puts extension_fichier_params
##type_produit.extension_fichier_ids = extension_fichier_params
#type_produit.extension_fichiers << ExtensionFichier.find_by(:id => extension_fichier_params)
respond_to do |format|
if #type_produit.save
format.html { redirect_to #type_produit, notice: 'Type produit was successfully created.' }
format.json { render :show, status: :created, location: #type_produit }
else
format.html { render :new }
format.json { render json: #type_produit.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /type_produits/1
# PATCH/PUT /type_produits/1.json
def update
respond_to do |format|
if #type_produit.update(type_produit_params)
format.html { redirect_to #type_produit, notice: 'Type produit was successfully updated.' }
format.json { render :show, status: :ok, location: #type_produit }
else
format.html { render :edit }
format.json { render json: #type_produit.errors, status: :unprocessable_entity }
end
end
end
# DELETE /type_produits/1
# DELETE /type_produits/1.json
def destroy
#type_produit.destroy
respond_to do |format|
format.html { redirect_to type_produits_url, notice: 'Type produit was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_type_produit
#type_produit = TypeProduit.find(params[:id])
end
def extension_fichier_params
#type_produit.extension_fichier_ids
end
# Never trust parameters from the scary internet, only allow the white list through.
def type_produit_params
params.require(:type_produit).permit(:nom, :extension_fichier_ids => [])
end
end
And here's the Rails server output:
Started POST "/type_produits" for 127.0.0.1 at 2015-01-27 17:55:15 +0100
Processing by TypeProduitsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"4LBhwTvGjXOq+3qzO+loGUV/oBCYjW66aVDeE1Zj/AM=", "type_produit"=>{"nom"=>"qsdfqsdf", "extension_fichier_ids"=>["1", "2", ""]}, "commit"=>"Create Type produit"}
ExtensionFichier Load (0.4ms) SELECT "extension_fichiers".* FROM "extension_fichiers" WHERE "extension_fichiers"."id" IN (1, 2)
------extension_fichier_params------
1
2
ExtensionFichier Load (0.2ms) SELECT "extension_fichiers".* FROM "extension_fichiers" WHERE "extension_fichiers"."id" IN (1, 2) LIMIT 1
(0.1ms) begin transaction
TypeProduit Exists (0.1ms) SELECT 1 AS one FROM "type_produits" WHERE "type_produits"."nom" = 'qsdfqsdf' LIMIT 1
SQL (0.4ms) INSERT INTO "type_produits" ("created_at", "nom", "updated_at") VALUES (?, ?, ?) [["created_at", "2015-01-27 16:55:15.923132"], ["nom", "qsdfqsdf"], ["updated_at", "2015-01-27 16:55:15.923132"]]
SQL (0.1ms) INSERT INTO "extension_fichiers_type_produits" ("extension_fichier_id", "type_produit_id") VALUES (?, ?) [["extension_fichier_id", 1], ["type_produit_id", 8]]
SQL (0.1ms) INSERT INTO "extension_fichiers_type_produits" ("extension_fichier_id", "type_produit_id") VALUES (?, ?) [["extension_fichier_id", 2], ["type_produit_id", 8]]
SQL (0.0ms) INSERT INTO "extension_fichiers_type_produits" ("extension_fichier_id", "type_produit_id") VALUES (?, ?) [["extension_fichier_id", 1], ["type_produit_id", 8]]
(0.5ms) commit transaction
Why is rails making 3 insert while it just has 2 objects

There's a very obvious error in your controller code. Let's go step by step through your create action.
You create a new TypeProduit from type_produit_params which includes :nom and :extension_fichier_ids. You then output the value of extension_fichier_params which itself is #type_produit.extension_fichier_ids and you get "1\n2\n" so your #type_produit already has both of those extension_fichiers attached to it.
You then append ExtensionFichier.find_by(:id => extension_fichier_params) to #type_produit.extension_fichier_ids. Now a find_by is basically a where().first so it gets only the first one, ie. id=1. So now in your #type_produit.extension_fichiers array you have ids 1, 2 and 1 again. Ie. three objects.
Then you save the TypeProduit and all three of those associations are saved with the three INSERTs.
And yeah, the overall solution to this (other than fixing your unnecessary << code or your model-or-view that's adding 1 and 2) is to add the -> { uniq } scope to your habtm association(s) as per https://stackoverflow.com/a/20226630/152786

Have you tried the solution suggested by using-uniq-in-a-has-and-belongs-to-many-relationship-in-rails-4 (and maybe also adding an index as suggested in has-and-belongs-to-many-avoiding-dupes-in-the-join-table ?)

Related

Save changes to tinymce inline editor in rails app?

I'm trying to save updates made in the inline tinymce editor in my rails app, but I don't know how to do it exactly as I want. I want the inline editor to be able to save while the view is 'html_safe'. I can save it fine if the form area is a text area (i.e. <div class="editor"><%= form.text_area :content %></div>), but I want to have the view in inline editor format so you can see your changes on the fly.
In the logs, it looks like the invitation params are closing before it's including the changes needed. How do I do this so that the inline editor changes are saved correctly?
Note: Everything else is working correctly, except the changes to the <%= #invitation.content %> are not being saved.
View:
<%= form_with(model: #invitation, local: true) do |form| %>
<%= form.hidden_field :event_id, value: #event.id %>
<div class="editor"><%= #invitation.content.html_safe %></div>
<script type="text/javascript">
tinyMCE.init({
selector: '.editor',
menubar: false,
inline: true,
plugins: "save",
toolbar: "save"
});
</script>
<% end %>
And my output from the log is:
Processing by InvitationsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"2ssewH/CSN7is0P2LVrMkEmwZXcgmQqjWTjgrE6gGqAEv4dmLXFjEuOFJ9TRia+JF59SB6kKu5Le1xvt/FoxPg==", "invitation"=>{"event_id"=>"29"}, "mce_0"=>"<h1>Second Test Event CHANGEHERE!</h1>\r\n<h2>09/02/18 # 04:20</h2>\r\n<p> </p>\r\n<hr />\r\n<p>Bring Cheese</p>", "commit"=>"Update Invitation", "id"=>"7"}
Invitation Load (2.6ms) SELECT "invitations".* FROM "invitations" WHERE "invitations"."id" = $1 LIMIT $2 [["id", 7], ["LIMIT", 1]]
↳ app/controllers/invitations_controller.rb:66
(0.3ms) BEGIN
↳ app/controllers/invitations_controller.rb:43
Event Load (1.8ms) SELECT "events".* FROM "events" WHERE "events"."id" = $1 LIMIT $2 [["id", 29], ["LIMIT", 1]]
↳ app/controllers/invitations_controller.rb:43
(0.3ms) COMMIT
↳ app/controllers/invitations_controller.rb:43
Redirected to http://localhost:3000/events/29
And my controller is a basic object controller:
class InvitationsController < ApplicationController
before_action :set_invitation, only: [:show, :edit, :update, :destroy]
# GET /invitations
# GET /invitations.json
def index
#invitations = Invitation.all
end
# GET /invitations/1
# GET /invitations/1.json
def show
end
# GET /invitations/new
def new
#invitation = Invitation.new
end
# GET /invitations/1/edit
def edit
end
# POST /invitations
# POST /invitations.json
def create
#invitation = Invitation.new(invitation_params)
respond_to do |format|
if #invitation.save
format.html { redirect_to #invitation, notice: 'Invitation was successfully created.' }
format.json { render :show, status: :created, location: #invitation }
else
format.html { render :new }
format.json { render json: #invitation.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /invitations/1
# PATCH/PUT /invitations/1.json
def update
respond_to do |format|
if #invitation.update(invitation_params)
format.html { redirect_to #invitation.event, notice: 'Invitation was successfully updated.' }
format.json { render :show, status: :ok, location: #invitation }
else
format.html { render :edit }
format.json { render json: #invitation.errors, status: :unprocessable_entity }
end
end
end
# DELETE /invitations/1
# DELETE /invitations/1.json
def destroy
#invitation.destroy
respond_to do |format|
format.html { redirect_to invitations_url, notice: 'Invitation was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_invitation
#invitation = Invitation.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def invitation_params
params.require(:invitation).permit(:name, :content, :event_id)
end
end

User signed in, but set to nil using Rails and Devise

devise (4.4.0)
Rails 5.1.4
I'm seeing this question asked a lot, but not finding the answer that works for me. I am showing that I am signing up and logging in, but current user set to nil. I'm thinking maybe it is the cookies, but I'm having a hard time parsing exactly how to fix that. One solution suggested adding
Rails.application.config.session_store :cookie_store, key: '_bejoy_session', domain: :all
to the config > session_store.rb which I did not have, but created and included. I'm just not sure what I'm missing here.
application controller:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :configure_permitted_parameters, if: :devise_controller?
helper_method :current_user
helper_method :admin
def current_user
if session[:user_id]
#current_user ||= User.find(session[:user_id])
end
end
def authorize
if !current_user
flash[:alert] = "You aren't authorized to visit that page."
redirect_to '/'
end
end
def admin_authorize
if !current_user || current_user.admin == false
flash[:alert] = "Only administrators can visit that page."
redirect_to new_user_session_path
end
end
def admin
current_user && current_user.admin
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:username, :admin, :email])
end
end
routes.rb
Rails.application.routes.draw do
root :to => 'contents#index'
resources :contents
resources :visitors
devise_for :users, controllers: {
sessions: 'users/sessions',
passwords: 'users/passwords',
registrations: 'users/registrations'
}
end
Terminal:
Started POST "/users/sign_in" for 127.0.0.1 at 2018-01-07 12:31:25 -0800
Processing by Users::SessionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"6a0yiBCkmEN0W68xN/lVZH71YhT5i5tMEkFFYqnoIvMU0NJjH3LM3hPG+8yO3D1tXskh9pSA+PRFVKDmiKzN6A==", "user"=>{"email"=>"test#tester.com", "password"=>"[FILTERED]", "remember_me"=>"0"}, "commit"=>"Log in"}
User Load (1.9ms) SELECT "users".* FROM "users" WHERE "users"."email" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["email", "test#tester.com"], ["LIMIT", 1]]
(0.1ms) BEGIN
SQL (2.0ms) UPDATE "users" SET "current_sign_in_at" = $1, "last_sign_in_at" = $2, "sign_in_count" = $3, "updated_at" = $4 WHERE "users"."id" = $5 [["current_sign_in_at", "2018-01-07 20:31:26.091228"], ["last_sign_in_at", "2018-01-07 20:29:10.402839"], ["sign_in_count", 5], ["updated_at", "2018-01-07 20:31:26.092407"], ["id", 2]]
(0.4ms) COMMIT
Redirected to http://localhost:3000/
Completed 302 Found in 152ms (ActiveRecord: 4.5ms)
Started GET "/" for 127.0.0.1 at 2018-01-07 12:31:26 -0800
Processing by ContentsController#index as HTML
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 2], ["LIMIT", 1]]
**current_user :nil
session id request :353a5e1d2bd295e8ac665e22e8f31314
user_signed_in? :false**
Rendering contents/index.html.erb within layouts/application
Content Load (0.2ms) SELECT "contents".* FROM "contents"
Rendered contents/index.html.erb within layouts/application (1.5ms)
Rendered partials/_author_photo_contact_block.html.erb (0.4ms)
Completed 200 OK in 53ms (Views: 49.1ms | ActiveRecord: 0.5ms)
contents controller:
class ContentsController < ApplicationController
before_action :authenticate_user!
# before_action :set_content, only: [:show, :edit, :update, :destroy]
def index
#contents = Content.all
logger.debug "current_user :#{current_user.inspect}"
logger.debug "session id request :#{request.session_options[:id]}"
logger.debug "user_signed_in? :#{user_signed_in?}"
end
def show
end
def new
#content = Content.new
end
def edit
end
def create
#content = Content.new(content_params)
respond_to do |format|
if #content.save
format.html { redirect_to #content, notice: 'Content was successfully created.' }
format.json { render :show, status: :created, location: #content }
else
format.html { render :new }
format.json { render json: #content.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #content.update(content_params)
format.html { redirect_to #content, notice: 'Content was successfully updated.' }
format.json { render :show, status: :ok, location: #content }
else
format.html { render :edit }
format.json { render json: #content.errors, status: :unprocessable_entity }
end
end
end
def destroy
#content.destroy
respond_to do |format|
format.html { redirect_to contents_url, notice: 'Content was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_content
#content = Content.find(params[:id])
end
def content_params
params.require(:content).permit(:main_image, :sidebar_image, :content, :sidebar)
end
end
Solution:
my current_user method in the application controller was overriding devise's own current_user method. I removed the current_user method I had in my application controller and it now shows:
current_user :#<User id: 2, email: "test#tester.com", username: "", admin: false, created_at: "2018-01-07 20:09:17", updated_at: "2018-01-07 21:33:51">
session id request :all
user_signed_in? :true
current user present? :true
found answer here: devise - can't display sign in or sign out in rails view

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 collection_select not working for many to one relationship

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

Rails: can`t get data in callback

I try to modify data before validation, but can't: by using self.param_name will be returned nil. My code:
class Category < ActiveRecord::Base
before_validation do
logger.info ":category_parameters before: #{self.category_parameters}"
self.category_parameters = self.category_parameters.split(/,/)
logger.info ":category_parameters after: #{self.category_parameters}"
end
end
Log file:
Started PATCH "/categories/9" for 127.0.0.1 at 2014-08-16 15:13:15 +0300
Processing by CategoriesController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"7RswlNAVs26W72IY6eL56xmACbVPCZQvl7MqDMueUbg=", "category"=>{"name"=>"Computers", "url"=>"computers", "category_parameters"=>"gergewrg,rewgwerg,wergwerg"}, "commit"=>"Save", "id"=>"9"}
Category Load (0.5ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = $1 LIMIT 1 [["id", 9]]
(0.3ms) BEGIN
:category_parameters before: []
:category_parameters after: [[]]
I use PostgreSQL and :category_parameters have type array in my schema:
create_table "categories", force: true do |t|
...
t.string "category_parameters", array: true
...
end
UPD:
Controller code:
class CategoriesController < ApplicationController
before_action :set_category, only: [:show, :edit, :update, :destroy]
...
def edit
end
...
def update
respond_to do |format|
if #category.update(category_params)
format.html { redirect_to #category, notice: 'Category was successfully updated.' }
format.json { render :show, status: :ok, location: #category }
else
format.html { render :edit }
format.json { render json: #category.errors, status: :unprocessable_entity }
end
end
end
...
private
# Use callbacks to share common setup or constraints between actions.
def set_category
#category = Category.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def category_params
params.require(:category).permit(:name, :url, :category_parameters)
end
end
Reserved
After talking on chat, it appears the original attribute name of category_parameters was reserved by Rails for some reason (hence why the OP couldn't populate it).
The fix was to change the attribute name in the db to nested_params, the strong_params reference, and finally the attributes in the view. Here is the result:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"7RswlNAVs26W72IY6eL56xmACbVPCZQvl7MqDMueUbg=", "category"=>{"name"=>"Computers", "url"=>"computers", "nested_params"=>"{123,123,123},{123,gwehrewrh,235235}"}, "commit"=>"Save", "id"=>"9"}
:nested_params before: ["123", "123", "123", "123", "gwehrewrh", "235235"]
:nested_params after: [["123", "123", "123", "123", "gwehrewrh", "235235"]]
Your category_parameters are not being passed as an array, they're being passed as a string.
You could try this...
params[:category][:category_parameters] = params[:category][:category_parameters].split(/,/)
params.require(:category).permit(:name, :url, category_parameters: [])
Do NOT do a before_validation record, as it will mess up your record every time you re-save it for any reason.
Changing your strong parameters to this format should solve your problem.
def category_params
params[:category][:category_parameters] = params[:category][:category_parameters].split!(',')
params.require(:category).permit(:name, :url, :category_parameters => [])
end

Resources