I have only one controller and some actions in it to handle different functionalities related to IMAP. So my problem is I don’t want to create a separate connection for every action. For example in an action I can do something like(it is not the actual code):
def index
@imap = Net::IMAP.new(server, 993, true)
@imap.login(user, password)
@imap.select("INBOX")
end
Again in another action inside the same controller, if I need to do something related to IMAP then I will have to create the @imap
variable again.
I am working with IMAP first time so as per my understanding new
method in each action will create another connection to the server and I have heard google has connection limit (15) for the number of IMAP connections.
I can not serialize this connection object or store it in any other service like Redis or Memcached or cache it, So how can I create this connection once and use it all other actions, at least actions inside the same controller if possible? If not possible then any other solutions to handle this problem?
And of course I can cache the data I need from the mailbox but that can’t help much since there are some other actions which won’t need the data, it will need to do so some operations in the mailbox like deleting mails, so that will need the connection instance.
2
Answers
How about you create a service object (singleton) that wraps you
Net::IMAP
. You can stick it inapp/services/imap_service.rb
or something like that. For an example on what that would look like:You access this singleton like
IMAPService.instance
e.g.IMAPService.instance.inbox(user, password)
. I added in the connect_pool gem as per our discussion to make sure this is thread safe. There is noattr_reader :imap
on IMAPService. However, you can add one so that you can directly access the connection pool in your code if you don’t want to include all of the necessary methods here (although I recommend using the service object if possible). Then you can doIMAPService.instance.imap.with { |conn| conn.login(user, password) }
and don’t need to rely on methods in IMAPService.It’s worth noting that you don’t have to use the
Singleton
mixin. There is a really good article on Implementing “the lovely” Singleton which will show you both ways to do it.If you want the connection to stay open between requests you can not store it as an instance variable in your controller since each request will have its own instance of the controller.
One way to store the connection is to use a singleton.
Here is an example:
This will open the connection the first time you access it, and if you access it again, it will use the old connection.
You would access the imap variable with
ImapService.instance.imap
anywhere in your application.