This is part of the Semicolon&Sons Code Diary - consisting of lessons learned on the job. You're in the caching category.
Last Updated: 2024-11-21
I was getting some bugs in my tests with code like the following. Specifically, the conversion wasn't tracking.
(All code gets executed in the same request, FYI)
module ApplicationHelper
def order_just_completed?(order)
@order_just_completed ||=
cookies.signed.delete(:order_just_completed).present? && order.present?
end
end
class AccountController
include ApplicationHelper
def show_downloads
# This call or order_just_completed? goes first and works
unless helpers.order_just_completed?(@order)
@possible_upgrades = @order.possible_upgrades
@possible_bundle_upgrades = @order.possible_bundle_upgrades
end
render "my_view"
end
end
View code:
# This call to order_just_completed? goes second and does not work...
<% if order_just_completed?(@order) %>
<%= tag.div(data: {
conversion: 'purchase', currency: @order.currency, value: @order.total.to_s, transaction_id: @order.number
}) %>
If you look closely at the order_just_completed?
function, it modifies the
session data after being called once. However it does cache the result in an
instance variable @order_just_completed
. The issue, then, is that this
instance variable, being in module, which itself has no instances, is only
available to whatever particular other class instance (e.g. controller) happened
to first call order_just_completed?
The code in the view file does not share
this module state.
To make this clearer notice how the caching is not shared across instances.
module SharedCode
def fav_number
@number ||= rand
end
end
class Dog
include SharedCode
end
class Cat
include SharedCode
end
Dog.new.fav_number
# e.g. 0.5010301301
Cat.new.fav_number
# e.g. 0.78122112
Essentially the same thing was happening in my Rails app.
The quick-fix solution was to use a global variable instead
module SharedCode
def fav_number
@_shared_code_cache_number ||= rand
end
end
Instance variable memoization inside a module/mixin will not carry over to other instances. Rethink your design or consider reaching for a global variable.