Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails 3: Passing belongs_to field in form, can't mass-assign protected attributes

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?

like image 814
Emily Bache Avatar asked Nov 30 '22 16:11

Emily Bache


2 Answers

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.

like image 62
DanneManne Avatar answered Jun 01 '23 17:06

DanneManne


'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
like image 41
Mischa Avatar answered Jun 01 '23 16:06

Mischa