Rails.cache.fetch does not work for array of json - ruby-on-rails

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|

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|

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.

Related

NoMethodError (undefined method `[]' for nil:NilClass) when object is not nil

My app consists in a form via which you can enter a word, submit, and then the controller will create a Word object with the word itself, and the definition and an example fetched via JSON from an API.
This is the conflicting line:
def create
#word = Word.new(word_params)
url = "http://api.pearson.com/v2/dictionaries/entries?headword=#{#word.word_name}"
Rails.logger.info url
uri = URI(url)
Rails.logger.info uri
response = Net::HTTP.get(uri)
Rails.logger.info response
result = ActiveSupport::JSON.decode(response)
Rails.logger.info result
#word.definition = result[0]["results"][0]["senses"][0]["definition"][0]
#word.example = result[0]["results"][0]["senses"][0]["translation"][0]["example"][0]["text"]
#word.save
redirect_to #word
end
And here comes the error line:
#word.definition = result[0]["results"][0]["senses"][0]["definition"][0]
FATAL -- :NoMethodError (undefined method `[]' for nil:NilClass):
So I assumed that result was nil. So I logged it out but the result is exactly as expected as shown in this image
What else can I try?
Use result["results"] instead of result[0]["results"]
#word.definition = result["results"][0]["senses"][0]["definition"][0]

Method calling helper method response

I have a method in my helper that returns rows of results. I want to pass this to a method in my model which is called by another method.
Helper Method:
def transactions(account_id, start, finish)
response = get_call('/Accounts/Statements/' + account_id.to_s + '/' + start + '/' + finish)
response = JSON.parse(response.body)
#transactions = response.map {|txn| Transaction.new(txn)}
return #transactions
end
Model Method I wish to call helper method into:
def transaction
??
end
Model Method which requires the transaction method:
def to_pdf
title = #account.name
subtitle = "Account Statement: #{#month_name} #{#year}"
StatementPDF.new(title, subtitle, #transactions).render
end
In the initialise section of this method i have added:
#transactions = {}
The Prawn PDF is now being generated but without the rows of results. Let me know if any other information is required.
You can reference your helpers from models using ApplicationController.helpers method:
ApplicationController.helpers.transactions(...)
This will solve your problem but, in my opinion, it would be much better, if you refactor your code and don't use helpers from model.

update function throwing erro(rails)

I am having a problem that when ever I call the update function it throws an error. I have tried to find the solution but I could'nt find it and I can't understad the error. Please tell me what is wrong with the code
The update function is called from this function
def bookmark_request
data = params[:d]
request_bookmarked = Request.getRequest(data)
bookmarked_against_Request = Request.first
request_bookmarked_2 = request_bookmarked
bookmarked_against_Request_2 = bookmarked_against_Request
if bookmarked_against_Request_2[:favourites]
bookmarked_against_Request_2[:favourites] << bookmarked_against_Request[:id]
else
bookmarked_against_Request_2[:favourites] = Array.new
bookmarked_against_Request_2[:favourites] << bookmarked_against_Request[:id]
end
Request.updateRequest(bookmarked_against_Request , bookmarked_against_Request_2)
redirect_to :action => "active"
end
and the update code is this
def updateRequest(request,req_data)
if request.update(req_data)
request
end
end
The error that I am getting is this
**NoMethodError at requests/bookmark_request
undefined method `empty?' for Request:0x007f3fa44c59b0**
The error always comes on the line if request.update(req_data)
Sice I do not have a reputation of 10 so I am posting links to screenshot of the error
http://tinypic.com/r/whbiv7/8
update() method's argument is expected to be a hash. But your req_data argument becomes actually a Request here:
def bookmark_request
bookmarked_against_Request = Request.first
...
bookmarked_against_Request_2 = bookmarked_against_Request
...
end
And Request class has no empty? method. Moreover it might become nil, if there are no Requests at all.

Handle bad JSON gracefully with Hash#fetch

I'm trying to fetch some products from this JSON API so I can display them in my views, with bad JSON gracefully handled using Hash#fetch to declare a default value if I get nil.
But why am I getting:
can't convert String into Integer
or if I set #json_text to {}:
undefined method 'fetch' for `nil:NilClass`
Live app: http://runnable.com/U-QEWAnEtDZTdI_g/gracefully-handle-bad-json
class MainController < ApplicationController
require 'hashie'
def index
#json_text = <<END
{
"products": []
}
END
hashes = JSON.parse(#json_text)
mashes = Hashie::Mash.new(hashes)
products = []
mashes.products.fetch('products', []).each do |mash|
puts "YOLO"
end
end
end
The right way to fetch is by calling fetch on mashes variable:
mashes.fetch('products', []).each do |mash|
puts "YOLO"
end
#fetch is a Hash method and in this case is the same as mashes['product'], except when product is nil, using the fetch example will return []

RubyAmf and Rails 3

I have recently been trying to upgrade my app form Rails 2.3.8 to newly-releases Rails 3.
After going through fixing some Rails 3 RubyAMF doesn't seem to work:
>>>>>>>> RubyAMF >>>>>>>>> #<RubyAMF::Actions::PrepareAction:0x1649924> took: 0.00017 secs
The action '#<ActionDispatch::Request:0x15c0cf0>' could not be found for DaysController
/Users/tammam56/.rvm/gems/ruby-1.9.2-p0/gems/actionpack-3.0.0/lib/abstract_controller/base.rb:114:in `process'
/Users/tammam56/.rvm/gems/ruby-1.9.2-p0/gems/actionpack-3.0.0/lib/abstract_controller/rendering.rb:40:in `process'
It doesn't seem to be able to find the proper controller. Might have to do with new changes in Rails 3 Router. Do you know how to go about finding the root cause of the problem and/or trying to fix it?
I'm pasting code from RubyAMF where this is happening (Exception happens at the line: #service.process(req, res)):
#invoke the service call
def invoke
begin
# RequestStore.available_services[#amfbody.service_class_name] ||=
#service = #amfbody.service_class_name.constantize.new #handle on service
rescue Exception => e
puts e.message
puts e.backtrace
raise RUBYAMFException.new(RUBYAMFException.UNDEFINED_OBJECT_REFERENCE_ERROR, "There was an error loading the service class #{#amfbody.service_class_name}")
end
if #service.private_methods.include?(#amfbody.service_method_name.to_sym)
raise RUBYAMFExc
eption.new(RUBYAMFException.METHOD_ACCESS_ERROR, "The method {#{#amfbody.service_method_name}} in class {#{#amfbody.service_class_file_path}} is declared as private, it must be defined as public to access it.")
elsif !#service.public_methods.include?(#amfbody.service_method_name.to_sym)
raise RUBYAMFException.new(RUBYAMFException.METHOD_UNDEFINED_METHOD_ERROR, "The method {#{#amfbody.service_method_name}} in class {#{#amfbody.service_class_file_path}} is not declared.")
end
#clone the request and response and alter it for the target controller/method
req = RequestStore.rails_request.clone
res = RequestStore.rails_response.clone
#change the request controller/action targets and tell the service to process. THIS IS THE VOODOO. SWEET!
controller = #amfbody.service_class_name.gsub("Controller","").underscore
action = #amfbody.service_method_name
req.parameters['controller'] = req.request_parameters['controller'] = req.path_parameters['controller'] = controller
req.parameters['action'] = req.request_parameters['action'] = req.path_parameters['action'] = action
req.env['PATH_INFO'] = req.env['REQUEST_PATH'] = req.env['REQUEST_URI'] = "#{controller}/#{action}"
req.env['HTTP_ACCEPT'] = 'application/x-amf,' + req.env['HTTP_ACCEPT'].to_s
#set conditional helper
#service.is_amf = true
#service.is_rubyamf = true
#process the request
rubyamf_params = #service.rubyamf_params = {}
if #amfbody.value && !#amfbody.value.empty?
#amfbody.value.each_with_index do |item,i|
rubyamf_params[i] = item
end
end
# put them by default into the parameter hash if they opt for it
rubyamf_params.each{|k,v| req.parameters[k] = v} if ParameterMappings.always_add_to_params
begin
#One last update of the parameters hash, this will map custom mappings to the hash, and will override any conflicting from above
ParameterMappings.update_request_parameters(#amfbody.service_class_name, #amfbody.service_method_name, req.parameters, rubyamf_params, #amfbody.value)
rescue Exception => e
raise RUBYAMFException.new(RUBYAMFException.PARAMETER_MAPPING_ERROR, "There was an error with your parameter mappings: {#{e.message}}")
end
#service.process(req, res)
#unset conditional helper
#service.is_amf = false
#service.is_rubyamf = false
#service.rubyamf_params = rubyamf_params # add the rubyamf_args into the controller to be accessed
result = RequestStore.render_amf_results
#handle FaultObjects
if result.class.to_s == 'FaultObject' #catch returned FaultObjects - use this check so we don't have to include the fault object module
e = RUBYAMFException.new(result['code'], result['message'])
e.payload = result['payload']
raise e
end
#amf3
#amfbody.results = result
if #amfbody.special_handling == 'RemotingMessage'
#wrapper = generate_acknowledge_object(#amfbody.get_meta('messageId'), #amfbody.get_meta('clientId'))
#wrapper["body"] = result
#amfbody.results = #wrapper
end
#amfbody.success! #set the success response uri flag (/onResult)
end
The best suggestion is to try rails3-amf. It currently is severely lacking in features in comparison to RubyAMF, but it does work and I'm adding new features as soon as they are requested or I have time.

Resources