0

I am trying to cache server API response using Rail.cache.fetch feature but it seems like just always 'nil' instead cached data. Method below runs one time, then always fails with 'access to nil class' kind error when I am trying to go through @my_api_data_ variable

def index
  api_statuses_

end
def api_statuses_
  Rails.cache.fetch('api_repsonse_m_', expires_in: 3.minute) do


      @mypairs_ = ['ticker1','ticker2', 'ticker3', 'ticker4', 'ticker5', 'ticker6', 'ticker7', 'ticker8', 'ticker9', 'ticker10']

      @my_api_data_ = []
      @my_api_data_poplr = []
      url = 'https://myserver.com/ticker/'

      @mypairs_.each do |item_|
        uri = URI(url + item_)
        response = Net::HTTP.get(uri)
        begin
          #response is like this {"status":"valu1","time":"valu2","data":"valu3"}
          myresult = JSON.parse(response)
        rescue JSON::ParserError

        end
        #Rails.logger.info myresult
        @my_api_data_.push(myresult);
      end

  end
end

I hope maybe someone knows why it goes bad each time

I tried to add line "@my_api_data_" right before the end of cache block. This is the same error I got on original circumstances:

I, [2018-01-13T19:29:14.384766 #5716]  INFO -- : Processing by Private::MydataController#index as HTML
I, [2018-01-13T19:29:14.403774 #5716]  INFO -- :   Rendered private/mydata/index.html.slim within layouts/mydatalayout_ (0.7ms)
I, [2018-01-13T19:29:14.403919 #5716]  INFO -- : Completed 500 Internal Server Error in 19ms
F, [2018-01-13T19:29:14.405077 #5716] FATAL -- : 
ActionView::Template::Error (undefined method `each' for nil:NilClass):
    37:         .row
    38:           /! Top head coin-boxes
    39:           .market-top-coin-boxes
    40:             - @my_api_data_.each do |pair_data|
Vitali Grabovski
  • 183
  • 1
  • 3
  • 14
  • 1
    can you return @my_api_data_ at the end of Rails.cache.fetch block – sethi Jan 13 '18 at 01:01
  • I've added. No error related to nil class but seems like no caching. Each time I press refresh button it loads newer data. I run "api_statuses_" method in single line of my controller., then I read @my_api_data_ in my slim_template – Vitali Grabovski Jan 13 '18 at 01:40
  • irrelevant comment but: why are do you keep adding _ at the end of variable and method names? – Tamer Shlash Jan 13 '18 at 06:56
  • Relevant comment: is this happening in development? if so, it might be because your cache store is set to `null_store`. – Tamer Shlash Jan 13 '18 at 06:58
  • I am working in production. I think no harm to use _ character in ruby methods names, isn't it? – Vitali Grabovski Jan 13 '18 at 19:29

2 Answers2

1

It seems that the problem here is that you have to return @my_api_data_ at the end of the block. Let check the code below:

def api_statuses_
  Rails.cache.fetch('api_repsonse_m_', expires_in: 3.minute) do
    @mypairs_ = ['ticker1','ticker2', 'ticker3', 'ticker4', 'ticker5', 'ticker6', 'ticker7', 'ticker8', 'ticker9', 'ticker10']

    @my_api_data_ = []
    @my_api_data_poplr = []
    url = 'https://myserver.com/ticker/'

    @mypairs_.each do |item_|
      uri = URI(url + item_)
      response = Net::HTTP.get(uri)
      begin
        #response is like this {"status":"valu1","time":"valu2","data":"valu3"}
        myresult = JSON.parse(response)
      rescue JSON::ParserError
      end
      #Rails.logger.info myresult
      @my_api_data_.push(myresult);
    end
    @my_api_data
  end
end

Note that the first time that you call the api_statuses_ method all the blocked will be executed, and the return value will be written to the cache under the api_repsonse_m_ key. So, the next time that you call api_statuses_, and if the time in expires_in has not expired, it will return the value save in the cache and the block will not be executed.

Also, could you show us where and how are you using this method? Showing the code and the error log could be great to understand the problem.

Updated: It seems that you are not using correctly this. You should call the api_statuses_ method in the index method under the MydataController controller, and save the return value to a variable that will be use in your view.

For instance:

module Private
  class MydataController
    def index 
      @api_statuses = api_statuses_
    end
  end
end

Then, in your view:

.row
  .market-top-coin-boxes
    - @api_statuses.each do |pair_data|
JesusTinoco
  • 11,288
  • 5
  • 30
  • 23
  • I added "@my_api_data" in the end of cache block, but I got the same error. However it does not raise error when I use "return @my_api_data", but this case no cachin at all! You can see my error log and updated information in my original post – Vitali Grabovski Jan 13 '18 at 19:37
  • 1
    You have to call to the method: `api_statuses_.each do |pair_data| ` – JesusTinoco Jan 14 '18 at 07:54
  • 1
    @VitaliGrabovski it seems that you are not using this method properly, could you check again my comment? I have update it. – JesusTinoco Jan 14 '18 at 08:01
1

Why are you using '@my_api_data_' in the view??

use

def index
  @result = api_statuses_
end

use @result in your view files. Note, if there is a cache hit the block passed to the Rails.cache.fetch is not run.

sethi
  • 1,869
  • 2
  • 17
  • 27