Reputation: 53
I have two model classes, Patient and Prescription, with a belongs_to relationship:
class Prescription
belongs_to :patient
...
I have a form for creating new Prescription objects, and I want it to get the patient from a hidden field:
<%= form_for(@prescription) do |f| %>
...
<%= f.hidden_field :patient_id, :value => @patient.id %>
...
In the prescriptions controller I want to create a new prescription using the params I got from the form:
def create
@prescription = Prescription.new(params[:prescription])
...
Something is not working. I can see in the log that the patient id is being passed in the params, but it is not getting inserted into the db:
Started POST "/prescriptions" for 127.0.0.1 at 2011-05-13 14:59:00 +0200 Processing by PrescriptionsController#create as HTML Parameters: {"utf8"=>"✓", "authenticity_token"=>"h3rizbBoW069EfvQf6NyzH53k+g4o4XO61jeZ/GF6t0=", "prescription"=>{"medicine_name"=>"w", "dispense_date(1i)"=>"2011", "dispense_date(2i)"=>"5", "dispense_date(3i)"=>"13", "days_supply"=>"2", "patient_id"=>"1"}, "commit"=>"Create Prescription"} WARNING: Can't mass-assign protected attributes: patient_id Patient Load (0.2ms) SELECT "patients".* FROM "patients" WHERE "patients"."id" IS NULL LIMIT 1 AREL (0.4ms) INSERT INTO "prescriptions" ("medicine_name", "dispense_date", "days_supply", "patient_id", "created_at", "updated_at") VALUES ('w', '2011-05-13', 2, NULL, '2011-05-13 12:59:00.690434', '2011-05-13 12:59:00.690434')
What does the warning message about mass-assign protected attributes mean? How do I change the code so it works?
Upvotes: 4
Views: 6007
Reputation: 21180
I think you have missed one of the great things about rails which would really help in this scenario. And that is the possibility to nest resources in the routing.
For example, if your routes.rb looks like this:
resources :patients do
resources :prescriptions
end
That would result in the url for your controller looking like /patients/:patient_id/prescriptions/
and the result of that is that since the patient_id is already existing in the url, you don't have to have any hidden form to store it. So in your PrescriptionsController, the create action could look like this:
def create
@patient = Patient.find(params[:patient_id])
@prescription = @patient.prescriptions.build(params[:prescription])
When you use the association to "build" the instance instead of directly with the model, it will automatically assign the patient_id for you.
This may not be the exact answer to your question but this is probably the way I would have done it.
Upvotes: 13
Reputation: 53
I didn't put enough in my code snippets, above. It turns out the problem was due to this in my model:
class Prescription:
belongs_to :patient
attr_accessible :medicine_name, :dispense_date, :days_supply
So I didn't have patient on the list of attr_accessible, and this caused the error message. I don't really understand what the attr_accessible is needed for, and everything worked if I removed it.
Thankyou for your comments, especially the one about the nested resources, I will look into that.
Upvotes: 1
Reputation: 43298
'Cannot mass-assign' means you cannot assign a value automatically like this:
# In the examples below @prescription.patient_id will not be set/updated
@prescription = Prescription.new(params[:prescription])
@prescription.update_attributes(params[:prescription])
You can solve this by setting :patient_id
as attr_accessible
in your Prescription
model. If you do this make sure you understand the security risks.
attr_accessible :patient_id
Or by assigning a value to patient_id
directly:
@prescription.patient_id = some_value
Upvotes: 7