Create two interdependent models from one form in rails - ruby-on-rails

I have used a combination of answers from 21222015, 17572279, 2663141, and RailsGuide to try and get multiple interdependent models to be created from a form.
In my application Users are used for authentication and Clinicians and Patients are models for the two different types of Users. Clinicians and Patients have almost no attributes in common so creating separate models made sense.
I would like to be able to create a patient or clinician and a user at the same time on a form. Patients and clinicians are both connected to their user by a user_id integer field.
Right now patients and clinicians belongs_to a user (patients also belongs_to a clinician and a clinician has_many patients):
class Patient < ActiveRecord::Base
belongs_to :clinician
belongs_to :user
def set_user_id_from_user
patient.user_id = user.id
end
before_validation :set_user_id_from_user
end
A user has_one patient or clinician:
class User < ActiveRecord::Base
has_secure_password
has_one :patient, :dependent => :destroy
has_one :clinician, :dependent => :destroy
accepts_nested_attributes_for :patient, :allow_destroy => true
accepts_nested_attributes_for :clinician, :allow_destroy => true
validates :email, presence: true
validates_uniqueness_of :email
end
I am trying to create a user and a patient on the new.html.erb - patients page using accepts_nested_attributes_for. I followed the RailsCast Nested Model Form Part 1 as it was recommended as an answer to SO question 10058584. This is my form:
<%= form_for #user do |form| %>
<p>
<div class="form-group">
<%= form.label :email %>
<%= form.text_field :email, class: "form-control", placeholder: "email address" %>
</div>
<div class="form-group">
<%= form.label :password %>
<%= form.password_field :password, class: "form-control", placeholder: "enter password" %>
</div>
</p>
<%= form.fields_for :patient do |builder| %>
<p>
<div class="form-group">
<%= builder.label :first_name %>
<%= builder.text_field :first_name, class: "form-control", placeholder: "First name" %>
</div>
<div class="form-group">
<%= builder.label :last_name %>
<%= builder.text_field :last_name, class: "form-control", placeholder: "Last name" %>
</div>
<div class="form-group">
<%= builder.label :diagnosis %>
<%= builder.text_field :diagnosis, class: "form-control", placeholder: "Diagnosis" %>
</div>
<div class="form-group">
<%= builder.label :gender_id %>
<%= builder.collection_select :gender_id, Gender.all, :id, :gender_type, :prompt => true, class: "form-control" %>
</div>
<div class="form-group">
<%= builder.label :age %>
<%= builder.text_field :age, class: "form-control", placeholder: "Age" %>
</div>
</p>
<% end %>
<%= form.button 'Create Patient', class: "btn btn-u btn-success" %>
<% end %>
In my UsersController I have:
def new
#user = User.new
end
def create
#user = User.create(user_params)
if #user.save
redirect_to user_path(#user), notice: "User created!"
else
render "new"
end
end
private
def user_params
params.require(:user).permit(:email, :password, patient_attributes: [ :first_name,:last_name,:user_id,:diagnosis,:gender_id,:age,:address, :email, :password, :phone_number, :caregiver_name, :other_symptom, :goals_of_care, :patient_deceased, :patient_archived ])
end
All of this currently gives me a form that only shows the two user fields: email and password. When submitted I get a new user created but no patient is created.
How do I get the patient fields to appear on the form and have a patient created that has a user_id that connects it to the user created at the same time?
Eventually I need to have it possible to create either a patient or a clinician when a user is created; maybe by making it so that that a patient/clinician accepts_nested_attributes_for a user and have the form for each?
Any advice would be really appreciated, thanks

I think that in order for your patient form fields to show up, you need to say #user.build_patient in your new action in your UsersController. This initializes a patient that is associated with the User instance you created.
In case it helps anyone else, if the relationship between patient and user was a has_many instead of a has_one, then the syntax would be #user.patient.build thenew action.

Related

Is this polymorphic association being set up correctly?

I have two account types with the relationship below laid out in models below. I need to build a registration form for #account that has a form select field where a user can select to register for either a student or partner account and for this account record to save according to the selection (i.e. to the students or partners table and the accounts table).
I'm running into issues on the controller Accounts#new method and I'm not sure how to set this up in a way that works.
Account:
class Account < ApplicationRecord
belongs_to :acct_holderable, :polymorphic => true
Student:
class Student < ApplicationRecord
has_one :account, :as => :acct_holderable
Partners:
class Partner < ApplicationRecord
has_one :account, :as => :acct_holderable
View for Accounts#new
<%= form_for(#account) do |f| %>
<%= render 'shared/error_messages', object: #account %>
<%= f.label :account_type %>
<%= f.select :acct_holderable, options_for_select(account_type, #account.account_holderable_type), class: 'form-control' %>
<%= f.label :first_name %>
<%= f.text_field :first_name, class: 'form-control' %>
<%= f.label :last_name %>
<%= f.text_field :last_name, class: 'form-control' %>
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
<%= f.submit yield(:button_text), class: "btn btn-primary" %>
<% end %>
Account Helper (for options_select)
def account_type
input =<<-OPTIONS
Student,
Partner,
Other Account TBU,
Other Account TBU
input.split(',')
end
Accounts controller
def new
#account = Account.new
end
def create
#account = Account.new(account_params)
if #account.save
#account.send_activation_email
flash[:info] = "Please check your email to activate your account before logging in!"
redirect_to login_url
else
render 'new'
end
end
Pls check the following link for more info http://guides.rubyonrails.org/association_basics.html#polymorphic-associations
https://6ftdan.com/allyourdev/2015/02/10/rails-polymorphic-models/
These links help you to get better understand about polymorphic association.

has_many :through and collection_select rails form

I have tried all of the solutions to similar problems and haven't gotten this one figured out.
I have a has_many :through relationship between 'Clinician', and 'Patient' with a joined model 'CareGroupAssignment'. None of the methods I have tried so far been able to save the clinician to patient association. I would like to have a patient be able to have multiple clinicians associated with it and clinicians will have multiple patients.
clinician.rb (simplified)
class Clinician < ActiveRecord::Base
belongs_to :care_group
has_many :patients ,:through=> :care_group_assignments
has_many :care_group_assignments, :dependent => :destroy
belongs_to :user
accepts_nested_attributes_for :user, :allow_destroy => true
end
patient.rb
class Patient < ActiveRecord::Base
belongs_to :care_group
has_many :clinicians ,:through=> :care_group_assignments
has_many :care_group_assignments
belongs_to :user
accepts_nested_attributes_for :user, :allow_destroy => true
end
care_group_assignments.rb
class CareGroupAssignment < ActiveRecord::Base
belongs_to :clinician
belongs_to :patient
end
I first tried to follow the example from Railscasts PRO #17- HABTM Checkboxes to at least start getting the data collected and to have the models set up correctly. Below is the form with the checkboxes for each clinician as described in the RailsCast, checkboxes show up and the data is sent but not stored (can't figure out why).
patient new.html.erb form
<%= form_for #patient do |form| %>
<%= form.fields_for :user do |builder| %>
<div class="form-group">
<%= builder.label "Email or Username" %>
<%= builder.text_field :email, class: "form-control" %>
</div>
<div class="form-group">
<%= builder.label :password %>
<%= builder.password_field :password, class: "form-control" %>
</div>
<% end %>
<div class="form-group">
<%= form.label :first_name %>
<%= form.text_field :first_name, class: "form-control", placeholder: "First name" %>
</div>
<div class="form-group">
<%= form.label :last_name %>
<%= form.text_field :last_name, class: "form-control", placeholder: "Last name" %>
</div>
<div class="form-group">
<% Clinician.where(care_group_id: #care_group.id).each do |clinician| %>
<%= check_box_tag "patient[clinician_ids][]", clinician.id, #patient.clinician_ids.include?(clinician.id), id: dom_id(clinician) %>
<%= label_tag dom_id(clinician), clinician.full_name %><br>
<% end %>
</div>
<%= form.button 'Create Patient', class: "btn btn-u btn-success" %>
<% end %>
Next, I tried the collection_select answer to this question. This creates a badly formatted list where only one clinician can be selected. The data seems to get sent but again doesn't save.
patient new.html.erb form
<div class="form-group">
<%= collection_select(:patient, :clinician_ids,
Clinician.where(care_group_id: #care_group.id).order("first_name asc"),
:id, :full_name, {:selected => #patient.clinician_ids, :include_blank => true}, {:multiple => true}) %>
</div>
Lastly, I copied what was done in this questions/solution. Also isn't formatted as a normal collection_select dropdown but instead a list with a boarder around it where only one clinician can be selected.
patient new.html.erb form
<div class="form-group">
<% Clinician.where(care_group_id: #care_group.id).each do |clinician| %>
<%= check_box_tag "patient[clinician_ids][]", clinician.id, #patient.clinician_ids.include?(clinician.id), id: dom_id(clinician) %>
<%= label_tag dom_id(clinician), clinician.full_name %><br>
<% end %>
</div>
None of these methods have so far been able to save the clinician to patient association.
patient_controller.rb
def new
#patient = Patient.new
#user = User.new
#patient.build_user
#care_group = current_clinician.care_group
end
def create
#patient = Patient.create(patient_params)
#patient.care_group = current_clinician.care_group
if #patient.save
redirect_to patient_path(#patient), notice: "New patient created!"
else
render "new"
end
end
def show
#patient = Patient.find_by(id: params["id"])
end
private
def patient_params
params.require(:patient).permit({:clinician_ids => [:id]},:first_name,:last_name,:user_id,:care_group_id, user_attributes: [ :email, :password, :patient_id, :clinician_id ])
end
I plan to display the clinicians associated with a patient on the patient show page:
patient show.html.erb
<strong>Shared with:</strong>
<% #patient.clinicians.each do |clinician| %>
<%= clinician.full_name %><
<% end %>
This works if I seed the database but since the data doesn't seem to be stored, nothing is showing up.
Rails 4.1.8, ruby 2.2.1p85, PostgreSQL
Thanks
Found the answer on another question I asked:
problem is this line in the controller:
params.require(:patient).permit({:clinician_ids => [:id]}...
It should be:
params.require(:patient).permit({:clinician_ids => []}...

has_many :throught not INSTERING INTO database from form

I have tried all of the solutions to similar problems and haven't gotten this one figured out.
I have a has_many :through relationship between 'Clinician', and 'Patient' with a joined model 'CareGroupAssignment'. I would like to have a patient be able to have multiple clinicians associated with it and clinicians will have multiple patients.
When I submit my form this is logged:
Started POST "/patients" for 127.0.0.1 at 2015-09-02 14:56:38 -0700
Processing by PatientsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"XXX=", "patient"=>{"user_attributes"=>{"email"=>"allencentre", "password"=>"[FILTERED]"}, "first_name"=>"Allen", "last_name"=>"Centre", "birth_date(1i)"=>"2002", "birth_date(2i)"=>"9", "birth_date(3i)"=>"2", "clinician_ids"=>["85", "87"], "patient_deceased"=>"0", "patient_archived"=>"0"}, "button"=>""}
So "clinician_ids"=>["85", "87"] is being passed from the form.
There is an INSERT INTO "users" ("email", .... and an INSERT INTO "patients" ("bir.... but the data for care_group_assignments doesn't have one.
There is [36mCareGroupAssignment Load (0.4ms)[0m [1mSELECT "care_group_assignments".* FROM "care_group_assignments" WHERE "care_group_assignments"."patient_id" = $1[0m [["patient_id", 199]]
clinician.rb (simplified)
class Clinician < ActiveRecord::Base
belongs_to :care_group
has_many :patients ,:through=> :care_group_assignments
has_many :care_group_assignments, :dependent => :destroy
belongs_to :user
accepts_nested_attributes_for :user, :allow_destroy => true
end
patient.rb
class Patient < ActiveRecord::Base
belongs_to :care_group
has_many :clinicians ,:through=> :care_group_assignments
has_many :care_group_assignments
belongs_to :user
accepts_nested_attributes_for :user, :allow_destroy => true
end
care_group_assignments.rb
class CareGroupAssignment < ActiveRecord::Base
belongs_to :clinician
belongs_to :patient
end
This is following the example from Railscasts PRO #17- HABTM Checkboxes to at least start getting the data collected and to have the models set up correctly. Below is the form with the checkboxes for each clinician as described in the RailsCast, checkboxes show up and the data is sent but not stored (can't figure out why).
patient new.html.erb form
<%= form_for #patient do |form| %>
<%= form.fields_for :user do |builder| %>
<div class="form-group">
<%= builder.label "Email or Username" %>
<%= builder.text_field :email, class: "form-control" %>
</div>
<div class="form-group">
<%= builder.label :password %>
<%= builder.password_field :password, class: "form-control" %>
</div>
<% end %>
<div class="form-group">
<%= form.label :first_name %>
<%= form.text_field :first_name, class: "form-control", placeholder: "First name" %>
</div>
<div class="form-group">
<%= form.label :last_name %>
<%= form.text_field :last_name, class: "form-control", placeholder: "Last name" %>
</div>
<div class="form-group">
<% Clinician.where(care_group_id: #care_group.id).each do |clinician| %>
<%= check_box_tag "patient[clinician_ids][]", clinician.id, #patient.clinician_ids.include?(clinician.id), id: dom_id(clinician) %>
<%= label_tag dom_id(clinician), clinician.full_name %><br>
<% end %>
</div>
<%= form.button 'Create Patient', class: "btn btn-u btn-success" %>
<% end %>
This method has so far not been able to save the clinician to patient association.
patient_controller.rb
def new
#patient = Patient.new
#user = User.new
#patient.build_user
#care_group = current_clinician.care_group
end
def create
#patient = Patient.create(patient_params)
#patient.care_group = current_clinician.care_group
if #patient.save
redirect_to patient_path(#patient), notice: "New patient created!"
else
render "new"
end
end
def show
#patient = Patient.find_by(id: params["id"])
end
private
def patient_params
params.require(:patient).permit({:clinician_ids => [:id]},:first_name,:last_name,:user_id,:birth_date, user_attributes: [ :email, :password, :patient_id, :clinician_id ])
end
I plan to display the clinicians associated with a patient on the patient show page:
patient show.html.erb
<strong>Shared with:</strong>
<% #patient.clinicians.each do |clinician| %>
<%= clinician.full_name %><
<% end %>
This works if I seed the database but since the data doesn't seem to be stored, nothing is showing up.
Rails 4.1.8, ruby 2.2.1p85, PostgreSQL
Thanks
I believe your problem is this line in your controller:
params.require(:patient).permit({:clinician_ids => [:id]}...
It should be:
params.require(:patient).permit({:clinician_ids => []}...

ActiveRecord associated objects not being saved when submitting form - Ruby on Rails

Im having problems with my child objects (scores) not being saved when submitting a form for a new (Qa).
Here are the models:
QA
belongs_to :user
has_many :scores, :dependent => :destory
has_many :call_components, through: :scores
accepts_nested_attributes_for :scores
Score
belongs_to :qa
has_one :call_component
Call Component Is just a title and description for a score
belongs_to :score
User
has_many :qas
has_many :scores, through: :qas
For whatever reason when submitting the post the scores are not created, the QA is however.
Form
<%= form_for [#qa], role: "form" do |f| %>
<%= f.label :call_id %>
<%= f.number_field :call_id, :autofocus => true, class: "form-control monospaced-control", placeholder: "Call Id", required: "" %>
... more fields
<% CallComponent.all.each do |comp| %> <!-- Usually is an array of about 5 components, so there 5 scores -->
<h4><b><%= comp.title.to_s.capitalize %></b></h4>
<p><%= comp.description.to_s.capitalize %></p>
<%= f.fields_for :scores, #qa.scores do |builder| %>
<%= builder.label :score, "Score" %>
<%= builder.number_field :score, :autofocus => true, class: "form-control monospaced-control", placeholder: "Score", required: ""%>
<%= builder.label :comments, "Comments" %><br />
<%= builder.text_area :comments, :autofocus => true, class: "form-control monospaced-control", placeholder: "Score", required: ""%>
<%= builder.hidden_field :call_component_id, :value => comp.id %>
<% end %>
<% end %>
Here is the QA New method
def new
#qa = Qa.new
#qa.scores.build
# Tried it this way too
##score = Score.new
##score.build_qa # then in the view linking the form like #score.qa, this didnt work.
end
And here is the QA Create Method
def create
#qa = Qa.new(qa_params)
#qa.final_score = #qa.scores.sum(:score).to_i
#qa.user_id = current_user.id
if #qa.save
redirect_to qas_path, notice: "New qa published!"
else
flash[:alert] = "Qa not published!"
render :new
end
end
def qa_params
params.require(:qa).permit(:call_id,...,:scores_attributes)
end
Any thoughts on how to fix this would be awesome. Thanks for your time.
try this..
def qa_params
params.require(:qa).permit(:agent_user_id, :call_id, :call_date, :case_number, :completion_date, scores_attributes: [:score,:comments,:call_component_id] )
end
as you need to specify which attributes of the nested set are permitted.

'Can't mass-assign protected attributes' when implementing Multiple Table Inheritance with nested forms

HI I am trying to implement the MTI in my application. I have a Person Model and 2 models inheriting from it: Client and TeamMember. When creating a Team Member I want to save to to database vallues for both person (first and last name, email etc) and team member(experience level, type of team, if lead or not). I am using the nested attributes form so in my team member form I am nesting the person fields. Unfortunatellly I am getting "Can't mass-assign protected attributes: person" error when trying to save. Can anyone tell me how this can be solved? Thanks!
Models:
UPDATED TeamMember class but still the same error
also tried people_attributes and persons_attributes and none of these worked
class TeamMember < ActiveRecord::Base
has_many :project_team_members
has_many :projects, through: :project_team_members
has_one :person, as: :profile, dependent: :destroy
accepts_nested_attributes_for :person
attr_accessible :person_attributes, :experience_level, :lead, :qualification, :team
end
class Person < ActiveRecord::Base
belongs_to :company
belongs_to :profile, polymorphic: true
attr_accessible :email, :first_name, :last_name, :phone_number, :profile_id, :profile_type
end
Controller as follows:
class TeamMembersController < ApplicationController
def create
person = Person.create! { |p| p.profile = TeamMember.create!(params[:team_member]) }
redirect_to root_url
end
and the view:
<%= form_for(#team_member) do |f| %>
<%= f.fields_for :person do |ff| %>
<div>
<%= ff.label :first_name %>
<%= ff.text_field :first_name %>
</div>
<div>
<%= ff.label :last_name %>
<%= ff.text_field :last_name %>
</div>
<div>
<%= ff.label :phone_number %>
<%= ff.text_field :phone_number %>
</div>
<div>
<%= ff.label :email %>
<%= ff.text_field :email %>
</div>
<div>
<%= ff.label :company_id %>
<%= ff.text_field :company_id %>
</div>
<% end %>
<div class="field">
<%= f.label :team %><br />
<%= f.text_field :team %>
</div>
<div class="field">
<%= f.label :experience_level %><br />
<%= f.text_field :experience_level %>
</div>
<div class="field">
<%= f.label :qualification %><br />
<%= f.text_field :qualification %>
</div>
<div class="field">
<%= f.label :lead %><br />
<%= f.check_box :lead %>
</div>
<div class="actions">
<%= f.submit %>
</div>
UPDATED TeamMembersController (Solution thanks to the courtesy of Tiago)
def new
#team_member = TeamMember.new
#team_member.build_person
respond_to do |format|
format.html # new.html.erb
format.json { render json: #team_member }
end
end
def create
#team_member = TeamMember.create!(params[:team_member])
redirect_to root_url
end
To mass assign attributes in a nested form, you'll need to specify:
class TeamMember < ActiveRecord::Base
has_many :project_team_members
has_many :projects, through: :project_team_members
has_one :person, as: :profile, dependent: :destroy
:experience_level, :lead, :qualification, :team #what is this line doing??
accepts_nested_attributes_for :person
attr_accessible :person_attributes
end
EDIT:
In the action called before the form you need to build person. Like:
#team_member = TeamMember.new
#team_member.build_person
Then you'll have one person (non-persisted) associated with #team_member.

Resources