-1

In my rails app I have answer_controller and connect_controller. app >controllers >answer_controller and app >controllers >connect_controller

My connect_controller has below code.

@url = api_version_root+'/members/all?council='+session[:council]
response = RestClient.get @url, api_token_hash
if response.code == 200
  @members = JSON.parse(response.body)
end

I want to access @members within answer_controller. How can I do this.

Dinu
  • 159
  • 1
  • 11
  • The same way that you get access @members in the connect controller would be the most appropriate way. the internet is stateless, you have to re-fetch everything needed for each request. Rails gives you a session variable that you can stuff things like a logged in users ID. The session is a cookie and can be accessed in any controller so maybe that could help you – jamesc Jul 14 '20 at 13:42

3 Answers3

2

A controllers instance variables are only present for a single request and only one controller action is called per request in Rails by design. This is also generally true of any framework/platform. If you want to persist anything between requests you need to either pass it along or store it somewhere as the thread responding to a request is terminated when it finishes serving a request and its variables are gone with it.

There are many ways to pass data from back and forth between the client and server like query string parameters, cookies and the session (stored in cookies by default). The size is strongly limited by the client such as the cookie size limit of roughly 4096 bytes and the defacto size limit of 2000 characters for URLs.

You can persist data on the server by using rails built in cache mechanism, a database, memory based storage (such as Memcached and Redis) or the servers file system.

Which to use depends on exactly how its being used, the size of the data and what architecticure you have in place.

max
  • 96,212
  • 14
  • 104
  • 165
0

I would use Rails caching, but you must think carefully about how to expire the cache. So:

@members = cached_members

private
def cached_members
  @url = api_version_root+'/members/all?council='+session[:council]
  Rails.cache.fetch("#{@url}/#{api_token_hash}/members", expires_in: 48.hours) do
    response = RestClient.get @url, api_token_hash
    (response.code == 200) && JSON.parse(response.body)
  end
end

Then duplicate this in the answer controller, and @members will be populated from the cache. Now, of course it's poor practice to actually duplicate code, so pull it out into a helper mixin, like:

module MemberCache
  def cached_members
    @url = api_version_root+'/members/all?council='+session[:council]
    Rails.cache.fetch("#{@url}/#{api_token_hash}/members", expires_in: 48.hours) do
      response = RestClient.get @url, api_token_hash
      (response.code == 200) && JSON.parse(response.body)
    end
  end
end

and include this in the two controllers:

require 'member_cache'
class ConnectController < ApplicationController
  include MemberCache
end
Les Nightingill
  • 5,662
  • 1
  • 29
  • 32
  • "The return value of the block will be written to the cache under the given cache key, and that return value will be returned." In your case you would write a boolean to the cache because of `(response.code == 200) && JSON.parse(response.body)`, no? – Christian Bruckmayer Jul 14 '20 at 06:46
  • Instead of a mixin I would also suggest to use a Plain Old Ruby Object (PORO) and use a similar interface than ActiveRecord. https://gist.github.com/ChrisBr/1a29a656d42dfabe96650ad75ce07856 – Christian Bruckmayer Jul 14 '20 at 06:52
  • @ChristianBruckmayer `true && "foo"` is `"foo"` not a boolean, so the value written to the cache is as intended. – Les Nightingill Jul 14 '20 at 12:14
  • @ChristianBruckmayer the PORO that you suggest would not have access to the `session` variable, so a mixin would be the way to go – Les Nightingill Jul 14 '20 at 12:15
  • I would be careful in asserting that the Rails cache is the ONLY answer here. There are many ways to skin a cat. – max Jul 14 '20 at 13:34
  • @max of course cache is not the ONLY answer. I've changed the wording in case someone might think that I'm saying that. – Les Nightingill Jul 14 '20 at 13:40
  • Didn't know about the `&&`, thanks! Regarding the session variable you can easily pass it into the PORO like `Member.where(council: session[:council])`. With a mixin you introduce coupling between your controllers and mixins so I would most of the time prefer a object oriented solution over a mixin. – Christian Bruckmayer Jul 14 '20 at 17:18
0

[MVC Model] On request, just one Controllers#action is called.

If you want to reuse a variable, put it to session


session[:members] = @members
rian
  • 370
  • 1
  • 6