Accessing a variable of one method in another in ruby on rails

I am facing an issue with accessing a particular variable of a method say A , in another method say B in the controller.. The size of the object(variable) is too big since it contains the results of a service call made.. My usecase is like on selecting an option from a drop down box, it redirects to a method B in controller and the same object(variable) should be parsed. How can I access the variable in the other method?

I tried storing in a cookie and since the size is too big I am getting Cookie Overflow exception. I am not using a DB. So I guess using memcache won't work. Also tried storing it as hidden field in view and passed its value as a data through ajax call. But I am getting it as a string. Tried to specify datatype as json and several other ways.. but of no use..Using @@var also din work..Not sure why..

Code:

On change of the drop down:

$(document).ready(function(){
    $('#filter_service').change(function() {
        $.ajax({type: "GET",
            url: "/device_troubleshootings/query_operation",
            data: { filter_service: $('# filter_service').val()},
        });
    });
});

Service call:

def log_results
  //Service call
  @get_log_results = LogQueryService.client.get_logs(Com::Amazon::Logqueryservice::DeviceSerialNumberQuery.new(:search_text => @ search , :index => 'dms', :index_type => '_all', :from_time_stamp =>  @from_time_stamp, :to_time_stamp => @to_time_stamp))
  @dsn_result = @get_log_results.logs_result_obj_list
end

Here, I am trying to access @dsn_result object in "/device_troubleshootings/query_operation” method.

Please suggest me ways to access the variable.


Solution 1:

MVC

I think you're getting confused with how Rails should work

Remember, Rails (which is just a framework for Ruby) is built on the "MVC" programming pattern. This means each time you send a request to your Rails application, it has to be handled by a single controller#action which you will then allow you to pull the relevant data from your models

The problem you have is you're trying to load multiple controller methods, and pass the same data to both. This might work in Ruby, but not Rails (Rails is stateless):

enter image description here

--

Model

The correct way to handle this type of setup is by creating another request for your application, which will load another controller#action, allowing you to access the data you need

As demonstrated by the MVC diagram above, each time you send a request to Rails, it's basically a new request. This means that unless you've persisted your data in the likes of a cookie, you'll need to load the data from the model.

The problem you have is you're trying to store an entire data-set in the front-end of your system. This issue is very bad, as not only is it inefficient, but it goes against the MVC pattern completely.

You'll be much better storing the bare-minimum data set you need in the front-end (ids or similar), which you will then be able send to your controller via ajax; building a new data-set from

--

Class Variables

You mentioned you tried to declare some @@class variables to no avail. The problem with this is that the class vars will only be available for an instance of a class.

As mentioned, since Rails is stateless, the class variables won't persist between requests (how can they?). I think you know this already, considering you've been trying to use cookies to store your data

The way to resolve this is to rebuild the data each time from the model (as detailed above)


Solution

The solution for you is to "go stateless"

Here's how:

  1. Treat Method A and Method B as completely separate "ACTIONS"
  2. When using these actions, you need to consider the smallest piece of data to pass between the two
  3. To load Method B, you need to send a new request from your browser (as if you've never loaded Method A before)

Your method_a can be handled in the "standard" way:

#config/routes.rb
resources :your_controller do
   collection do
      get :method_a
      get :method_b
   end
end

This will mean that you can load method_a relatively simply:

#app/controllers/your_controller.rb
Class YourController < ApplicationController
   def method_a
      @get_log_results = LogQueryService.client.get_logs(Com::Amazon::Logqueryservice::DeviceSerialNumberQuery.new(:search_text => @ search , :index => 'dms', :index_type => '_all', :from_time_stamp =>  @from_time_stamp, :to_time_stamp => @to_time_stamp))
      @dsn_result = @get_log_results.logs_result_obj_list
   end
end

As you know, the @dsn_result will not persist through to the next request.

There are two ways to resolve this (set a CONSTANT -- if you're pulling from an API, this will give you a single call -- or use a before_action to set the variable for as many actions as you need). I'll detail both for you:

#app/controllers/your_controller.rb
Class YourController < ApplicationController
    before_action :set_log_data

    def method_a
    end
    
    def method_b
    end
   
    private

    def set_log_data
       @get_log_results = LogQueryService.client.get_logs(Com::Amazon::Logqueryservice::DeviceSerialNumberQuery.new(:search_text => @ search , :index => 'dms', :index_type => '_all', :from_time_stamp =>  @from_time_stamp, :to_time_stamp => @to_time_stamp))
       @dsn_result = @get_log_results.logs_result_obj_list
    end
end

This will work if you pull data from your own data-set (using the models), however, the better way to do this in your case will likely be to set a constant (considering, of course, that you don't want the data to change):

#config/initializers/dsn_result.rb
get_log_results = LogQueryService.client.get_logs(Com::Amazon::Logqueryservice::DeviceSerialNumberQuery.new(:search_text => @ search , :index => 'dms', :index_type => '_all', :from_time_stamp =>  @from_time_stamp, :to_time_stamp => @to_time_stamp))
DSN_RESULT = get_log_results.logs_result_obj_list