Search code examples
ruby-on-railsdevisenested-resources

Nested resources, undefined method nilClass


I am getting an error "undefined method " when I try to build a nested resource on action 'new' in rails 4.2

Here's my routes:

devise_for :medics
resources :patients, shallow: true do
  resources :consultations do
    resources :prescriptions
  end 
end

I have Devise for system logon, and rather than use "User" to the model name, I use "Medic" in order to use the registry to devise to create a type of medical profile with a new fields like name, phone, etc. (I don't know if here's the problem)...

Patients controller:

class PatientsController < ApplicationController
before_action :set_medic

def new
  @patient = @medic.patients.new
end

def create
  @patient = @medic.patients.new(patient_params)
end

def set_medic
  @medic = Medic.find_by_id(params[:medic_id])
end

Model:

class Medic < ActiveRecord::Base
  devise :database_authenticatable, :registerable,
       :recoverable, :rememberable, :trackable, :validatable
  has_many :patients, :dependent => :destroy
end

class Patient < ActiveRecord::Base
  belongs_to :medic, :foreign_key => :medic_id, :dependent => :destroy
  has_many :consultations
  accepts_nested_attributes_for :consultations
end

View:

<%= link_to 'New Patient', new_patient_path(@medic) %>

rake routes:

 new_patient GET    /patients/new(.:format)   patients#new

Error:

undefined method `patients' for nil:NilClass

in this line: @patient = @medic.patients.new

Any idea? thaks in advance


Solution

  • The problem is very simple.

    You're calling the following on each request:

    def set_medic
      @medic = Medic.find_by_id(params[:medic_id])
    end
    

    The problem is that you're not passing medic_id through your routes:

    devise_for :medics
    resources :patients, shallow: true do #-> no medic_id here
      resources :consultations do         #-> or here
        resources :prescriptions          #-> or here
      end 
    end
    

    Therefore, what happens is that you're trying to find a Medic without any id, hence the NilClass error.


    You're getting confused with the nested resources directive in Rails routes:

    #DON'T use this - it's just an example
    #config/routes.rb
    resources :medics do 
       resources :patients #-> url.com/medics/:medic_id/patients/:id
    end
    

    As you're using Devise, I think you'd be able to get away with scoping your calls around the current_medic helper (which is what I presume you're doing)...

    -

    Fix

    #app/controllers/patients_controller.rb
    class PatientsController < ApplicationController
        def new
           @patient = current_medic.patients.new
        end
    
        def create
          @patient = current_medic.patients.new(patient_params)
        end
    end
    

    This way, you'll be able to use (as you're using current_medic):

    <%= link_to "New", new_patient_path %>