Search code examples
ruby-on-railsjbuilder

Missing partial error for existing file with Rails/JBuilder


I'm having a problem rendering a JSON partial with JBuilder (version ~>2.0) on Rails 4.2. It's giving me the ActionView missing partial error despite the file existing, it appears to be ignoring the path I provide and searching the default magic path. I realise that putting the partial at the magic path would fix it, but for a number of reasons it would be preferable to keep the partial where it is and find it correctly. The partial is being found correctly from elsewhere in my /views directory structure (specifically from /views/api/task_templates/_task_template.json.jbuilder).

Main JBuilder file, which is itself a partial (_task_template.json.jbuilder):

json.task_files task_template.task_files.each do |file|
  json.partial! file, partial: 'api/task_files/task_file', as: :task_file
end

Partial file (_task_file.json.jbuilder):

json.(task_file, :id, :file_type, :name, :original_path, :image_path, :icon, :organization_id, :viewer)

Error message:

ActionView::Template::Error:
        Missing partial api/v1/task_files/_task_file with {:locale=>[:en], :formats=>[:json], :variants=>[], :handlers=>[:jbuilder]}. Searched in:
          * "/Users/lucy/trail-app/app/views"
          * "/Users/lucy/.rvm/gems/ruby-2.1.3@trail-app/gems/sidekiq_monitor-0.1.7/app/views"
          * "/Users/lucy/.rvm/gems/ruby-2.1.3@trail-app/gems/devise_invitable-1.7.0/app/views"
          * "/Users/lucy/.rvm/gems/ruby-2.1.3@trail-app/gems/devise-4.2.0/app/views"

And this is my directory structure:

/views > /api > /task_files > _task_file.json.jbuilder (THE MISSING PARTIAL)
              > /v1         > /task_templates > _task_template.json.jbuilder (THE MAIN FILE)

Solution

  • I finally found the answer to this in the depths of the Ruby documentation while looking for something completely different, so I am recording it here for anyone that might come looking for an answer.

    Don't even bother giving the partial option in the JBuilder file. Add a method, to the class you are making a partial of, called to_partial_path. That method should return a string of the path to the partial you want.

    For example, in my case:

    Main JBuilder file:

    json.task_files task_template.task_files.each do |file|
      json.partial! file, as: :task_file
    end
    

    In the TaskFile model (task_file.rb):

    class TaskFile
      def to_partial_path
        'api/task_files/task_file'
      end
    end
    

    And the partial file remains the same. That works.