Reputation: 33
So in my rails project, I have a Patient class, which has one Treatment class. This treatment class then has many DrNotes inside of it. I am still fairly new to rails, and I am aware that nesting this deeply is not recommended in Rails, but I am proceeding with this method.
My problem is with the editing of DrNotes. Since there are many doctor notes within treatment, I am trying to only edit one specific note. I am using Form_for to pass parameters to the doctor's note. When I submit the form, it redirects me to the page that should be shown only when the update function has succeeded. However, none of the notes are actually updated, and no errors are thrown when I try to perform the update.
Here are the models in question:
patient.rb
class Patient < ApplicationRecord
has_one :treatment, dependent: :destroy
accepts_nested_attributes_for :treatment, update_only: true
end
treatment.rb
class Treatment < ApplicationRecord
belongs_to :patient
has_many :dr_notes, class_name: "DrNote",
foreign_key: "treatment_id", dependent: :destroy
accepts_nested_attributes_for :dr_notes
end
dr_note.rb
class DrNote < ApplicationRecord
belongs_to :treatment
end
In my controller I have:
Doctor Note Edit Function
def edit_dr_note
@patient = Patient.find(params[:patient_id])
@dr_note = @patient.treatment.dr_notes.find(params[:dr_id])
@dr_note.update if @dr_note.nil?
end
Doctor Note Update Function
def update_dr_note
@patient = Patient.find(params[:patient_id])
@dr_note = @patient.treatment.dr_notes.find(params[:dr_id])
if @dr_note.update(dr_note_params)
redirect_to page_path(@patient)
else
flash.now[:error] = "Cannot update Doctor's notes"
render 'edit_dr_note'
end
end
Doctor Note Params
def dr_note_params
params.require(:dr_note).permit(:id, :name, :message)
end
I have :id in the params.permit because from researching, I heard that you need to include it when updating models, but i'm not sure if it is needed here.
I have the following code in the routes.rb
get '/pages/:patient_id/treatment/edit/edit_dr_note/:dr_id', to: 'pages#edit_dr_note', as: :edit_dr_note
match "pages/:patient_id/treatment/update/update_dr_note/:dr_id" => "pages#update_dr_note", as: :update_dr_note, via: [:patch, :post]
And in the edit_dr_note.html.erb
<%= form_for @patient.treatment.dr_notes.find(params[:dr_id]), url: update_dr_note_path do |patient_form| %>
<% @patient.treatment.dr_notes.each do |doctor| %>
<% if doctor.id == @dr_note.id %> #Only displays the fields for the desired note
<%= patient_form.fields_for :dr_note, doctor do |doctor_fields| %>
Name: <%= doctor_fields.text_field :name %>
Message: <%= doctor_fields.text_field :message %>
<% end %>
<p>
<%= patient_form.submit %>
</p>
<% end %>
<% end %>
<% end %>
Any help would be greatly appreciated. Thanks!
Upvotes: 3
Views: 55
Reputation: 33552
You are mixing two approaches(the nested resources and the nested attributes). Use one to serve your purpose.
With the nested resources:
<%= form_for [:pages, @patient, @treatment, @dr_note], url: update_dr_note_path do |dr_note| %>
Name: <%= dr_note.text_field :name %>
Message: <%= dr_note.text_field :message %>
<p>
<%= dr_note.submit %>
</p>
<% end %>
The routes would be
get '/pages/:patient_id/treatment/:treatment_id/edit_dr_note/:dr_id', to: 'pages#edit_dr_note', as: :edit_dr_note
match "pages/:patient_id/treatment/:treatment_id/update_dr_note/:dr_id" => "pages#update_dr_note", as: :update_dr_note, via: [:patch, :post]
Edit the edit_dr_note
to define @treatment
def edit_dr_note
@patient = Patient.find(params[:patient_id])
@treatment = @patient.treatment
@dr_note = @patient.treatment.dr_notes.find(params[:dr_id])
@dr_note.update if @dr_note.nil?
end
And finally remove accepts_nested_attribute_for
from the models, you don't need it in this approach.
With the nested attributes:
Keep the accepts_nested_attributes_for
in the models. And change the routes and form like below
get '/edit_dr_note/:dr_id', to: 'pages#edit_dr_note', as: :edit_dr_note
match "/update_dr_note/:dr_id" => "pages#update_dr_note", as: :update_dr_note, via: [:patch, :post]
And the form_for
<%= form_for @patient, url: update_dr_note_path do |patient| %>
<%= patient.fields_for :treatment do |t| %>
<%= t.fields_for :dr_notes, @dr_note do |dr_note| %>
Name: <%= dr_note.text_field :name %>
Message: <%= dr_notetext_field :message %>
<% end %>
<% end %>
<p>
<%= patient.submit %>
</p>
<% end %>
And change the dr_note_params
method as below
def dr_note_params
params.require(:patient).permit(:id, treatment_attributes: [:id, dr_notes_attributes: [:id, :name, :message])
end
Upvotes: 1
Reputation: 12719
When you write the following line, you're trying to find
a DrNote
using the dr_id
:
@dr_note = @patient.treatment.dr_notes.find(params[:dr_id])
Whereas the dr_notes
relation on Treatment
does not seem to define any particular behavior, and this is your problem.
You'll need to find_by
doctor's id (or dr_id
in your code) and thus first define the relation on DrNote
.
Upvotes: 0