mike9182
mike9182

Reputation: 289

Rails: ActiveModel Error when creating new record

I have one controller (patients) that passes a patient_id to another controller (referral_requests) to use in building the referral request record. I am running into the following error when trying to create the referral request. What am I doing wrong? My referral_requests table includes an integer column for user_id.

I have multiple user types defined with enums. Staff users create both patients and referral requests.

Thanks for any help!

error:

(0.1ms)  rollback transaction
#<ActiveModel::Errors:0x007fe696696fc0 @base=#<ReferralRequest id: nil, content: nil, user_id: nil, created_at: nil, updated_at: nil, patient_id: 4, call_option_1: nil, call_option_2: nil, call_option_3: nil, call_option_1_status: nil, call_option_2_status: nil, call_option_3_status: nil, status: "created">, @messages={:user_id=>["can't be blank"]}, @details={:user_id=>[{:error=>:blank}]}>

patients controller create action:

def create
  @patient = current_user.patients.build(patient_params)
  if @patient.save
    flash[:success] = "Patient Created!"
    redirect_to new_referral_request_path(patient_id: @patient.id)
  else
    Rails.logger.info(@patient.errors.inspect)
    render 'patients/new'
end

referral_requests controller new and create actions, and params:

def new
  @patient = Patient.find(params[:patient_id]) 
  @referral_request = current_user.referral_requests.build(patient:  @patient) if signed_in?
end

def create
  @referral_request = current_user.referral_requests.build(referral_request_params)
  if @referral_request.save
        flash[:success] = "Referral Request Created!"
        redirect_to new_dispatch_path(referral_request_id:   @referral_request.id)
  else
    Rails.logger.info(@referral_request.errors.inspect)
    @feed_items = []
    render 'static_pages/home'
  end
end

private

def referral_request_params
  params.require(:referral_request).permit(:content, :user_id, :patient_id, concern_ids: [], insurance_ids: [], race_ids: [], language_ids: [], gender_ids: [])
end

Here are the model relationships:

require 'active_support/concern'

module StaffUser
  extend ActiveSupport::Concern

  included do
    has_many :referral_requests, foreign_key: "user_id"

class ReferralRequest < ApplicationRecord
  belongs_to :user, -> { where role: :staff }, class_name: 'User', foreign_key: 'user_id'

Upvotes: 0

Views: 291

Answers (2)

Michael Chaney
Michael Chaney

Reputation: 3031

"user_id" shouldn't be in your permitted parameters list.

edit:

The actual issue from the comments is that he's validating the presence of "user_id" instead of "user". When creating a record through an association the id won't be filled in until later in the process, so you just check for the presence of the associated item rather than the id:

validates :user, presence: true

Upvotes: 1

max
max

Reputation: 101851

If you are creating referrals for a patient you should make it a nested resource:

resources :patients do
  resources: :referral_requests, shallow: true
end

Since creating this resource should require authentication you want to make sure to handle that in a before filter:

class ReferralRequestsController < ApplicationController
  before_action :authenticate_user!
end

If you are rolling your own authentication solution rather than using Devise, make sure you have such a method:

class ApplicationController
  private
  def authenticate_user!
    redirect_to new_session_path and return unless current_user
  end
end

When we create the resource note that we are not taking the user_id (provided by the session) nor the patient id (we get it from the path segment) from the form input.

class ReferralRequestsController < ApplicationController
  before_action :authenticate_user!
  before_action :set_patient, only: [:new, :create, :index]

  # GET /patients/:patient_id/referral_requests/new
  def new
    @referral_request = @patient.referral_requests.new
  end

  # POST /patients/:patient_id/referral_requests
  def create
    @referral_request = @patient.referral_requests.new(referral_request_params) do |rr|
      rr.user = current_user
    end

    if @referral_request.save
      flash[:success] = "Referral Request Created!"
      redirect_to new_dispatch_path(referral_request_id:   @referral_request.id)
    else 
      Rails.logger.info(@referral_request.errors.inspect)
      @feed_items = []
      render :new
    end
  end

  private
  def set_patient
    @patient = Patient.find(params[:patient_id])
  end

  def referral_request_params
     params.require(:referral_request)
        .permit(:content, 
           concern_ids: [], 
           insurance_ids: [], 
           race_ids: [], 
           language_ids: [], 
           gender_ids: []
        )
  end
end

Using a before filter will here will also validate that the patient exists since Patient.find(params[:patient_id]) will raise ActiveRecord::RecordNotFound.

A good way to handle where a record should be created with user input and other values such a user id from the session is to pass a block:

@referral_request = @patient.referral_requests.new(referral_request_params) do |rr|
  rr.user = current_user
end

Allowing the user_id param from the form would make it possible for a malicious user to pass any user id by just altering the input with the web inspector!

You create the proper path in the form by passing an array:

<%= form_for([@patient, @referral_request]) do |f| %>

Upvotes: 1

Related Questions