has_many :through and collection_select rails form - ruby-on-rails

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 => []}...

Related

Validation failed: Stocks product must exist, Stocks location must exist

I have three models -> locations, products and stocks.
Stocks is a join table of locations and products.
When creating a new product i used fields_for to show locations and even though i got it to work, for some reason now it does not seem to work anymore and it gives me the above error.
<div class="input-field">
<%= f.label :product_name %>
<%= f.text_field :name, autofocus: true %>
</div>
<div class="input-field">
<%= f.label :price %>
<%= f.text_field :price, autofocus: true %>
</div>
<% if !#edit %>
<%= f.fields_for :stocks do |ff| %>
<div class="input-field margin-top x-4">
<%= ff.collection_select :location_id, Location.all, :id, :structured_location , {:prompt => "Please Select Locations for Product"}, {multiple: true} %>
<%= ff.label :locations %>
</div>
<div class="input-field">
<%= ff.label :quantity %>
<%= ff.text_field :quantity %>
</div>
<div class="input-field">
<%= ff.label :threshold_quantity %>
<%= ff.text_field :threshold_quantity %>
</div>
<% end %>
<% else %>
<%= collection_select :product, :location_ids, Location.all, :id, :structured_location , {:prompt => "Please Select Locations for Product"}, {multiple: true} %>
<% end %>
<div class="row margin-top x-4">
<div class="col s12 center-align">
<%= f.submit "#{current_page?(new_product_path) ? "Create Product" : "Update Product"}", class: "btn wave-effect pink darken-1 btn-large" %>
</div>
</div>
controller
class ProductsController < ApplicationController
helper_method :sort_column, :sort_direction
def index
#products = Product.order(sort_column + " " + sort_direction)
end
def new
#product = Product.new
#product.stocks.build
end
def create
#product = Product.new(product_params)
if #product.save!
flash[:notice] = "Successfully saved..."
redirect_to products_path
else
flash[:alert] = "Something went wrong, please check the values you entered"
redirect_to :back
end
end
private
def product_params
params.require(:product).permit(:name,:price, location_ids: [], stocks_attributes: [:id, :quantity, :threshold_quantity, location_id: []])
end
end
product model
class Product < ApplicationRecord
has_many :stocks, dependent: :destroy
has_many :locations, :through => :stocks
accepts_nested_attributes_for :stocks
end
parameters in rails console
Parameters: {"utf8"=>"✓",
"authenticity_token"=>"l1BFhrdyB2QMO5k3+60GNiPphFfF+DXDGPbUU3V2Op2aekObjgIe13k8uoedmDIEZgIeXPZUeS/0VxQXkKa1Uw==",
"product"=>{"name"=>"Soap", "price"=>"10", "location_ids"=>["", "1",
"2"], "stocks_attributes"=>{"0"=>{"quantity"=>"100",
"threshold_quantity"=>"100"}}}, "commit"=>"Create Product"}
After hours of searching i stumbled upon this post
BigBinary
it seems that Rails 5 made belongs_to relationship IDs required by default thats why i had validations failed and i couldn't find anything about it.
simply adding optional: true in my stock model worked!
class Stock < ApplicationRecord
belongs_to :location, optional: true
belongs_to :product, optional: true
accepts_nested_attributes_for :product, allow_destroy: true
accepts_nested_attributes_for :location, allow_destroy: true
end

Rails ActiveRecord 'slightly' complex Association

I would like to structure a music web-application's database to use the following structure.
Song(Attributes: name, year, etc(any other relevant attributes))
has many Performances
has many Performers (through Performances)
has many Artists (through Performers)
Performance(Foreign key:Song_id, Attributes: enum version: [:official, :remix, :cover])
belongs to Song
has many Performers
has many Artists (through Performers)
Performers (Foreign keys: Performance_id, Artist_id, Attributes: enum role: [:main_artist, :collaborating_artist, :featuring_artist, :versus ])
has one Song (through Performers)
belongs to Performances
belongs to Artist
Artist(Attributes: name, DOB, etc.(any other relevant attributes))
has many Performers
has many Performances (through Performers)
has many Songs (through Performances)
So that upon saving a Song, i can have all the rest of the other tables populated too, that is via the associations, however, so far i had the following implementations:
Song model:
class Song < ActiveRecord::Base
#Added to make the db more logical and ended up complicated
has_many :performances
has_many :performers, :through => :performances
has_many :artists, :through => :performers
accepts_nested_attributes_for :artists, allow_destroy: true
accepts_nested_attributes_for :performers, allow_destroy: true
accepts_nested_attributes_for :performances, allow_destroy: true
validates :name, :presence => true, uniqueness: true
validates :year, :presence => true
end
Performance model:
class Performance < ActiveRecord::Base
enum version: [:official, :remix, :cover]
belongs_to :song
has_many :performers
has_many :artists, :through => :performers
end
Performer model:
class Performer < ActiveRecord::Base
enum role: [:main_artist, :collaborating_artist, :featuring_artist, :versus]
belongs_to :artist
belongs_to :performance
has_one :song, :through => :performers #this upsets the back hairs!
end
Artist model:
class Artist < ActiveRecord::Base
#Added to make the db more logical and ended up complicated
has_many :performers
has_many :performances, :through => :performers
has_many :songs, :through => :performances
validates :name, :presence => true, uniqueness: true
end
Song controller
class SongsController < ApplicationController
before_action :find_song, only: [:show, :edit, :update, :destroy]
def index
...
end
def new
#song = Song.new
#song.performers.build
#song.performances.build
#genres = Genre.all #.map{|c| [ c.name, c.id ] }
#countries = Country.all.map{|c| [ c.name, c.id ] }
end
def create
#song = Song.new(song_params)
if #song.save
redirect_to #song, notice: 'Successfully added a song.'
else
render 'new'
end
end
def show
...
end
def update
if #song.update(song_params)
redirect_to #song, notice: 'Successfully updated the song.'
else
render 'edit', notice: 'Unable to save the changes'
end
end
def edit
...
end
def destroy
...
end
private
def song_params
params.require(:song).permit(:name, :year, artists_attributes: [ :id, :name, :DOB], performances_attributes: [:id, :version, :song_id], performers_attributes: [:id, :performance_id, :artist_id])
end
def find_song
#song = Song.find(params[:id])
end
end
new.html.erb
<div class="content">
<%= form_for #song, html: { multipart: true } do |f| %>
<% if #song.errors.any? %>
<div>
<%= #song.errors.count %>
Prevented this song from saving
<ul>
<% #song.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name, class: "input-field" %>
</div>
<div class="song-version">
<div class="field">
<%= f.fields_for :performances do |performances_for_form| %>
<%= render 'performances_fields', f: performances_for_form %>
<% end %>
</div>
</div>
<div class="performers-fields">
<h2>Artist(s)</h2>
<div class="field">
<%= f.fields_for :performers do |performers_for_form| %>
<%= render 'performers_fields', f: performers_for_form %>
<% end %>
</div>
</div>
<div class"btn">
<%= f.submit %>
</div>
<% end %>
</div>
Performance partial
<fieldset>
<div class="field">
<%= f.label :version %>
<%= f.select :version, Performance.versions.keys %>
</div>
</fieldset>
Performer partial
<fieldset>
<h2>Artists Details</h2>
<div class="field">
<%= f.fields_for :artists do |artists_for_form| %>
<%= render 'artist_fields', f: artists_for_form %>
<% end %>
</div>
<div class="field">
<%= f.label :artists_role %>
<%= f.select :role, Performer.roles.keys %>
</div>
</fieldset>
Artist partial
<fieldset>
<div class="field">
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :DOB %>
<%= f.datetime_select :DOB, :ampm => true, :minute_step => 15 %>
</div>
</fieldset>
When I fill out all the data on the form, upon saving, only the Song's attributes and Performances attributes are saved to the database, while the Performers & Artists are never saved, neither is the connection established, my questions are:
Is this structure logically correct? If not what is it that is being incorrectly done.
Is the new, create methods of songs_controller wrongly implemented and thus, the reason for not being able to save the data appropriately?
What right and or best practices could be employed developing this type of web-application with this kind of database structure?
Or is there any other better or succinct database structure that would better be followed rather than this?

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 => []}...

Create two interdependent models from one form in 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.

Rails 3 autocomplete gem with belongs_to association

I am using the rails3-jquery-autocomplete gem and it works neat when using it for fields that exist in the model. However, I have been trying to use it for associations and I fail to see how to make it work. So let's explain what I have:
Models:
class Receipt < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
has_many :receipts
end
Controller
class Admin::ReceiptsController < AdminController
autocomplete :user, :name
def index
#receipts = Receipt.all
end
def show
#receipt = Receipt.find_by_id(params[:id])
end
def edit
#receipt = Receipt.find_by_id(params[:id])
#users = User.all
end
end
View (form):
<%= form_for(#receipt, :url => admin_receipt_path, :html => { :multipart => true }) do |f| %>
<div class="clearfix">
<%= f.label :value, "Value($)" %>
<div class="input"><%= f.text_field :value %></div>
</div>
<div class="clearfix">
<%= f.label :user_id, "User" %>
<div class="input">
<%= f.autocomplete_field :user_id, autocomplete_user_name_admin_receipts_path %>
</div>
</div>
.....
The thing is... I am able to fetch user names, but I want to actually store the user id in there. The same way I would like to show the name when the admin tries to edit an existing receipt with a user associated. Something that I am able to do with this drop down:
<div class="clearfix">
<%= f.label :user_id, "User" %>
<div class="input"><%= f.select :user_id, #users.collect {|p| [ p.name, p.id ] },{:prompt => 'Select a User'} %></div>
</div>
I am failing to see how would I do this with this gem....
Ryan Bates did a screencast on this. Clean and well explained
Screencast
If you don't feel like subscribing try torrent

Resources