grape icon indicating copy to clipboard operation
grape copied to clipboard

NoMethodError in after callback inside Grape::Middleware::Formatter

Open Bilal-Abbas-Gigalabs opened this issue 4 years ago • 14 comments

I am getting Grape::Middleware::Formatter : undefined method `collect' for #<Stream:0x00007f685ce13270> My code works fine, I have tested each line by my hand but if I run the whole API this error appears. My code is as follow

        @stream = Stream.new(stream_params)
        @stream.location_id = get_location
        @stream.user_id = @streamer.id
        @stream.university = @university
        @stream.category = @category
        @stream.save!
        status(200){
          'message': 'successfully created the stream request'
        }

Bilal-Abbas-Gigalabs avatar Dec 14 '20 17:12 Bilal-Abbas-Gigalabs

@Bilal-Abbas-Gigalabs which version of Grape and Rack do you use?

dnesteryuk avatar Dec 15 '20 07:12 dnesteryuk

rack (~> 2.0, >= 2.0.8)
grape (1.5.1)
      activesupport
      builder
      dry-types (>= 1.1)
      mustermann-grape (~> 1.0.0)
      rack (>= 1.3.0)
      rack-accept
    grape-active_model_serializers (1.5.2)
      active_model_serializers (>= 0.10.0)
      grape (>= 0.8.0)
    grape_devise_token_auth (0.1.4)
      devise (>= 3.3)
      devise_token_auth (>= 0.1.32)
      grape (> 0.9.0)
    grape_on_rails_routes (0.3.2)
      rails (>= 3.1.1)
    groupdate (5.2.1)
      activesupport (>= 5)
    i18n (1.8.5)
      concurrent-ruby (~> 1.0)

Bilal-Abbas-Gigalabs avatar Dec 15 '20 09:12 Bilal-Abbas-Gigalabs

I think this is because your method returns the stream somehow.

Noticing that status does not take a block. Try this:

... # your code that does something to Stream
status 200
{ 'message': 'successfully created the stream request' }

dblock avatar Dec 15 '20 13:12 dblock

Still getting the same error on above update !!!

Bilal-Abbas-Gigalabs avatar Dec 15 '20 13:12 Bilal-Abbas-Gigalabs

Post the full stack please?

dblock avatar Dec 15 '20 14:12 dblock

caught error of type NoMethodError in after callback inside Grape::Middleware::Formatter : undefined method `collect' for #<Stream:0x00007fdc60daa630>
  
NoMethodError (undefined method `collect' for #<Stream:0x00007fdc60daa630>):
  
activemodel (6.0.3.4) lib/active_model/attribute_methods.rb:432:in `method_missing'
grape (1.5.1) lib/grape/middleware/formatter.rb:47:in `block in build_formatted_response'
activesupport (6.0.3.4) lib/active_support/notifications.rb:182:in `instrument'
grape (1.5.1) lib/grape/middleware/formatter.rb:46:in `build_formatted_response'
grape (1.5.1) lib/grape/middleware/formatter.rb:30:in `after'
grape (1.5.1) lib/grape/middleware/base.rb:39:in `call!'
grape (1.5.1) lib/grape/middleware/base.rb:29:in `call'
grape (1.5.1) lib/grape/middleware/base.rb:36:in `call!'
grape (1.5.1) lib/grape/middleware/base.rb:29:in `call'
grape_devise_token_auth (0.1.4) lib/grape_devise_token_auth/middleware.rb:14:in `call'
grape (1.5.1) lib/grape/middleware/auth/base.rb:37:in `_call'
grape (1.5.1) lib/grape/middleware/auth/base.rb:19:in `call'
grape (1.5.1) lib/grape/middleware/error.rb:39:in `block in call!'
grape (1.5.1) lib/grape/middleware/error.rb:38:in `catch'
grape (1.5.1) lib/grape/middleware/error.rb:38:in `call!'
grape (1.5.1) lib/grape/middleware/base.rb:29:in `call'
rack (2.0.9) lib/rack/head.rb:12:in `call'
grape (1.5.1) lib/grape/endpoint.rb:231:in `call!'
grape (1.5.1) lib/grape/endpoint.rb:225:in `call'
grape (1.5.1) lib/grape/router/route.rb:58:in `exec'
grape (1.5.1) lib/grape/router.rb:116:in `process_route'
grape (1.5.1) lib/grape/router.rb:72:in `block in identity'
grape (1.5.1) lib/grape/router.rb:91:in `transaction'
grape (1.5.1) lib/grape/router.rb:70:in `identity'
grape (1.5.1) lib/grape/router.rb:55:in `block in call'
grape (1.5.1) lib/grape/router.rb:132:in `with_optimization'
grape (1.5.1) lib/grape/router.rb:54:in `call'
grape (1.5.1) lib/grape/api/instance.rb:167:in `call'
grape (1.5.1) lib/grape/api/instance.rb:71:in `call!'
grape (1.5.1) lib/grape/api/instance.rb:66:in `call'
grape (1.5.1) lib/grape/api.rb:68:in `call'
actionpack (6.0.3.4) lib/action_dispatch/routing/mapper.rb:19:in `block in <class:Constraints>'
actionpack (6.0.3.4) lib/action_dispatch/routing/mapper.rb:48:in `serve'
actionpack (6.0.3.4) lib/action_dispatch/journey/router.rb:49:in `block in serve'
actionpack (6.0.3.4) lib/action_dispatch/journey/router.rb:32:in `each'
actionpack (6.0.3.4) lib/action_dispatch/journey/router.rb:32:in `serve'
actionpack (6.0.3.4) lib/action_dispatch/routing/route_set.rb:834:in `call'
warden (1.2.9) lib/warden/manager.rb:36:in `block in call'
warden (1.2.9) lib/warden/manager.rb:34:in `catch'
warden (1.2.9) lib/warden/manager.rb:34:in `call'
rack (2.0.9) lib/rack/etag.rb:25:in `call'
rack (2.0.9) lib/rack/conditional_get.rb:38:in `call'
rack (2.0.9) lib/rack/head.rb:12:in `call'
activerecord (6.0.3.4) lib/active_record/migration.rb:567:in `call'
actionpack (6.0.3.4) lib/action_dispatch/middleware/callbacks.rb:27:in `block in call'
activesupport (6.0.3.4) lib/active_support/callbacks.rb:101:in `run_callbacks'
actionpack (6.0.3.4) lib/action_dispatch/middleware/callbacks.rb:26:in `call'
actionpack (6.0.3.4) lib/action_dispatch/middleware/executor.rb:14:in `call'
actionpack (6.0.3.4) lib/action_dispatch/middleware/actionable_exceptions.rb:18:in `call'
actionpack (6.0.3.4) lib/action_dispatch/middleware/debug_exceptions.rb:32:in `call'
actionpack (6.0.3.4) lib/action_dispatch/middleware/show_exceptions.rb:33:in `call'
railties (6.0.3.4) lib/rails/rack/logger.rb:37:in `call_app'
railties (6.0.3.4) lib/rails/rack/logger.rb:26:in `block in call'
activesupport (6.0.3.4) lib/active_support/tagged_logging.rb:80:in `block in tagged'
activesupport (6.0.3.4) lib/active_support/tagged_logging.rb:28:in `tagged'
activesupport (6.0.3.4) lib/active_support/tagged_logging.rb:80:in `tagged'
railties (6.0.3.4) lib/rails/rack/logger.rb:26:in `call'
actionpack (6.0.3.4) lib/action_dispatch/middleware/remote_ip.rb:81:in `call'
request_store (1.5.0) lib/request_store/middleware.rb:19:in `call'
actionpack (6.0.3.4) lib/action_dispatch/middleware/request_id.rb:27:in `call'
rack (2.0.9) lib/rack/runtime.rb:22:in `call'
activesupport (6.0.3.4) lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call'
actionpack (6.0.3.4) lib/action_dispatch/middleware/executor.rb:14:in `call'
actionpack (6.0.3.4) lib/action_dispatch/middleware/static.rb:126:in `call'
rack (2.0.9) lib/rack/sendfile.rb:111:in `call'
actionpack (6.0.3.4) lib/action_dispatch/middleware/host_authorization.rb:82:in `call'
rack-cors (1.1.1) lib/rack/cors.rb:100:in `call'
railties (6.0.3.4) lib/rails/engine.rb:527:in `call'
puma (4.3.7) lib/puma/configuration.rb:228:in `call'
puma (4.3.7) lib/puma/server.rb:713:in `handle_request'
puma (4.3.7) lib/puma/server.rb:472:in `process_client'
puma (4.3.7) lib/puma/server.rb:328:in `block in run'
puma (4.3.7) lib/puma/thread_pool.rb:134:in `block in spawn_thread'

Bilal-Abbas-Gigalabs avatar Dec 15 '20 14:12 Bilal-Abbas-Gigalabs

I don't know how your Stream object is making this to the formatter part. Your code above creates it, assigns it to some @stream and then is done with it? Or are you returning it elsewhere? Post the complete API class?

Does the API return a result successfully without any of the stream = ... code?

I think you'll have to put up something that reproduces the problem from here for us to help.

dblock avatar Dec 15 '20 14:12 dblock

That is my end point

    # ----------------------------------------------------
    # POST /
    # ----------------------------------------------------
    #
    desc 'Create stream request'
    post '/' do
      authenticate_api_admin_user!
        init_create
        @stream = Stream.new(stream_params)
        @stream.location_id = get_location
        @stream.user_id = @streamer.id
        @stream.university = @university
        @stream.category = @category

        unless params[:user][:streamImage].nil?
          s3 = Aws::S3::Resource.new(region:'eu-west-2')
          extension = params[:user][:streamImage][:filename].split('.').last
          filename = SecureRandom.uuid + "." + extension
          image = s3.bucket('communy-file-storage').object("stream_images/" + filename)
          image.upload_file(params[:user][:streamImage][:tempfile])
          @stream.stream_image = image.public_url.to_s
        end
        
        set_temp_date_to_stream

        survey = Survey.find(ActiveSupport::JSON.decode(params[:user][:survey])["id"]) if 
        ActiveSupport::JSON.decode(params[:user][:survey]).present?
        @stream.survey = survey if survey.present?

        @stream.save!

        @notification = Notification.new()
        @notification.title = "New Stream Request!"
        @notification.text = "Your university admin has invited you for a stream."
        @notification.type = Notification.types[:stream_request_from_university]
        @notification.user_id = @streamer.id

        @notification.save!

        assign_secondary_categories
        @stream_request = StreamRequest.new(stream_request_params)
        @stream_request.save!
        assign_time_ranges

        status 200
        {
          'message': 'successfully created the stream request'
        }
    end

Follwoing are my helpers

helpers do
    def stream_params
      @stream_params ||= {
        name: ActiveSupport::JSON.decode(params[:user][:title]),
        overview: ActiveSupport::JSON.decode(params[:user][:description]),
        publish_status: ActiveSupport::JSON.decode(params[:user][:isPublished]) ? 'broadcasted' : 'draft',
        streamer_status: 'waiting',
        agora_status: 'standby',
        stream_type: ActiveSupport::JSON.decode(params[:user][:streamType]) == 'Webinar' ? 1 : 0,
        repeat_stream: ActiveSupport::JSON.decode(params[:user][:repeatStream]).nil? ? 'None' : 
      ActiveSupport::JSON.decode(params[:user][:repeatStream])
      }
    end

    def update_stream_params
      @update_stream_params ||= {
        name: ActiveSupport::JSON.decode(params[:user][:title]),
        overview: ActiveSupport::JSON.decode(params[:user][:description]),
        repeat_stream: ActiveSupport::JSON.decode(params[:user][:repeatStream]).nil? ? 'None' : 
        ActiveSupport::JSON.decode(params[:user][:repeatStream]),
        category_id: ActiveSupport::JSON.decode(params[:user][:primaryCategory])
      }
    end

    def stream_request_params
      @stream_request_params ||= {
        requester: current_api_admin_user,
        requestee: @streamer,
        status: ActiveSupport::JSON.decode(params[:user][:isPublished]) ? 'pending' : 'draft',
        stream: @stream,
        from_university: true
      }
    end

    def location_params
      @location_params ||= {
        place: ActiveSupport::JSON.decode(params[:user][:location]),
        university_id: @university.id
      }
    end

    def init_create
      @university = current_api_admin_user.profession_university
      unless @university
        error!('This user is not assigned to any university', 404, nil)
      end

      @streamer = User.find(ActiveSupport::JSON.decode(params[:user][:streamer])["id"])
      unless @streamer
        error!('Streamer can not find', 404, nil)
      end

      @category = Category.find(ActiveSupport::JSON.decode(params[:user][:primaryCategory]))
      unless @category
        error!('Category can not find', 404, nil)
      end
    end

    def init_update
      @stream = Stream.find(ActiveSupport::JSON.decode(params[:user][:id]))
      unless @stream
        error!("There is no stream with this id #{ActiveSupport::JSON.decode(params[:user][:id])}", 404, nil)
      end

      @stream_request = StreamRequest.find_by_stream_id(@stream.id)
      unless @stream_request
        error!('There is no stream_request about this stream', 404, nil)
      end

      @university = current_api_admin_user.profession_university
      unless @university
        error!('This user is not assigned to any university', 404, nil)
      end
    end

    def get_location
      location = Location.where(place: ActiveSupport::JSON.decode(params[:user][:location]))
                         .where(university_id: @university.id)

      if location.empty?
        location = Location.new(location_params)
        location.save!
      else
        location = location.first
      end
      location.id
    end

    def set_temp_date_to_stream
      favorite_time_range_option = ActiveSupport::JSON.decode(params[:user][:availableTimes]).find { |t| t["isFavorite"] }

      unless favorite_time_range_option
        error!('There should be at least one favorite available time', 404, nil)
      end

      @stream.starts_at = Time.at(favorite_time_range_option["startTs"]).to_datetime
      @stream.ends_at = Time.at(favorite_time_range_option["endTs"]).to_datetime
    end

    def assign_time_ranges
      @stream_request.time_ranges.clear
      ActiveSupport::JSON.decode(params[:user][:availableTimes]).each do |time_range|
        start_ts = Time.at(time_range["startTs"]).to_datetime
        end_ts = Time.at(time_range["endTs"]).to_datetime

          @stream_request.create_time_ranges(start_ts, end_ts, time_range["isFavorite"])
      end
    end

    def assign_secondary_categories
      if ActiveSupport::JSON.decode(params[:user][:secondaryCategories]).present?
        secondary_categories = @stream.secondary_categories
        secondary_categories.destroy_all
        ActiveSupport::JSON.decode(params[:user][:secondaryCategories])&.each do |category|
          next unless Category.find(category["id"])

          SecondaryCategory.create(stream: @stream, category_id: category["id"])
        end
      end
    end
  end

and one model method

def create_time_ranges(start_hour, end_hour, is_favorite)
    time_range = TimeRange.new(start_hour: start_hour, end_hour: end_hour,
                               favorite: is_favorite, stream_request_id: id)
    time_range.save!
    time_ranges << time_range
  end

I ran each an every line of code in debugging and it did not gave me this error This error occurs when the request got completed

Bilal-Abbas-Gigalabs avatar Dec 15 '20 14:12 Bilal-Abbas-Gigalabs

I am just creating the stream along with a request whose code is listed and that is it. Nothing else

Bilal-Abbas-Gigalabs avatar Dec 15 '20 14:12 Bilal-Abbas-Gigalabs

I don't see anything wrong, but there's a lot going on. I would delete everything to start in the API body, make sure that works, then slowly re-add parts of the code to narrow it down.

dblock avatar Dec 15 '20 14:12 dblock

Sure thank you I will wait for that.

Bilal-Abbas-Gigalabs avatar Dec 15 '20 14:12 Bilal-Abbas-Gigalabs

Sorry, I meant you should do that. I will wait to hear what you find.

dblock avatar Dec 15 '20 14:12 dblock

Weirdly enough, I have a model called Stream too and this is happening to me, sharing none of the above code. @Bilal-Abbas-Gigalabs did you manage to solve it? @dblock perhaps?

chrisedington avatar Jun 22 '22 14:06 chrisedington

Hi, I also encountered the same error.

In my case, it was because I had defined @stream in my code.

In such a situation,

I hope this helps. Thank you.

n1sym avatar Oct 17 '22 10:10 n1sym