Search code examples
ruby-on-railsrubydecoratordraper

Draper::UninferrableDecoratorError (Could not infer a decorator)


I want to infer a decorator in a controller, so I generate a decorator the normal way (rails g decorator) and infer it in the controller. However, when I test with Postman, I get the error:

Could not infer a decorator for Employers::Job.

The error message shows that my syntax in the controller is incorrect (where .decorate is used), I don't know where I am going wrong.

I have tried changing the way of writing and specifying the decorator explicitly ( @job = Employers::JobDecorator.find(params[:id]).decorate), but again this gives a NoMethodError (undefined method `find' for Employers::JobDecorator:Class).

This is part of the controller:

  def show
    @job = @employer.jobs.find(params[:id])
    render json: @job
  end
end

This is the decorator at the beginning:

  def attributes
    #somethings
  end

UPDATE 2 Thanks to the suggestion in the comments, things changed after I used Employers::JobDecorator.decorate(@job) in the controller, but I got a new error. The message says undefined method 'attributes' for nil:NilClass, the source is a line of code from the following file:

#app/decorators/employer/job_decorator.rb

  def attributes
    super.merge(
      {
        id: nil, 
        emp: nil, 
      }).delete_if { |k, v| 
          ['class_name'].include?(k)
        }
  end

What is the reason for this?

UPDATE 3

Following the advice of the comments, I got back to the previous error after changing some of the decorators to the following.

  def attrs
    model.attributes.merge(
      {

The error is "NoMethodError in Employers::JobController#show", and the file pointed to is one of the lines in "config/initializer/active_model/serialization.rb" (last line extracted below):

module ActiveModel
   module Serialization
     def serializable_hash(options = nil)
       options ||= {}

       attribute_names = attributes.keys

UPDATE 4

If I change the way decorator is written, the result is still similar to "undefined method `id' for #Employers::JobDecorator:0x00007ff3cdd3f748"

class Employers::JobDecorator < Draper::Decorator
  delegate_all

  def attributes
    {
      id:           nil,
      name:         nil,
      slug:         nil
    }
  end

end

UPDATE 5

I suspect the reason is that @job is nil, so I added something to the controller, finally solved the problem. I got it in the wrong direction.


Solution

  • Draper infers the decorator from the object that is decorated and in your scenario is Employers::Job.

    Because the decorator you want to be used has a totally different name, Api::V2::Employers::JobDecorator, you need to explicitly specify it.

    So, Api::V2::Employers::JobDecorator.decorate(@job) is what you need.

    More information, here