Scope and Instance Variable Question

Hail Caesars!

I’m wondering why the instance variable “@spree_invoice_number” is out
of scope in both the authorize and the create_transaction methods in
the appended code. Both of the aforementioned methods are called after
the create_profile method, where the instance variable is
initialized. I checked to make sure the instance variable name is
unique in both the application and the gem repository.

Thanks in advance for any suggestions!


class Gateway::AuthorizeNetCim < Gateway
#unabridged version of this file is here:

attr_accessor :spree_invoice_number

def provider_class
self.class
end

def options
# add :test key in the options hash, as that is what the
ActiveMerchant::Billing::AuthorizeNetGateway expects
if self.prefers? :test_mode
self.class.default_preferences[:test] = true
else
self.class.default_preferences.delete(:test)
end
super
end

def authorize(amount, creditcard, gateway_options)
create_transaction(amount, creditcard, :auth_only )
# spree_invoice_number is nil within this method:
# create_transaction(amount, creditcard, :auth_only, :order =>
{:invoice_number => @spree_invoice_number} )
end

Create a new CIM customer profile ready to accept a payment

def create_profile(payment)
@spree_invoice_number = payment.order.number
if payment.source.gateway_customer_profile_id.nil?
profile_hash = create_customer_profile(payment)
logger.debug(“create_profile @spree_invoice number:
#{@spree_invoice_number}\n” )
profile_hash[:customer_address_id] =
create_customer_shipping_profile(profile_hash[:customer_profile_id],
payment)
payment.source.update_attributes(:gateway_customer_profile_id =>
profile_hash[:customer_profile_id], :gateway_payment_profile_id =>
profile_hash[:customer_payment_profile_id], :address_id =>
profile_hash[:customer_address_id], :invoice_number =>
@spree_invoice_number
)
end
#successfully prints variable to log
can_access_instance_variable_here
end

simpler form

def create_profile_from_card(card)
if card.gateway_customer_profile_id.nil?
profile_hash = create_customer_profile(card)
card.update_attributes(:gateway_customer_profile_id =>
profile_hash[:customer_profile_id])
end
end

def can_access_instance_variable_here
logger.debug(“can_access_instance_variable_here @spree_invoice
number: #{@spree_invoice_number}\n” )
end

private

# Create a transaction on a creditcard
# Set up a CIM profile for the card if one doesn't exist
# Valid transaction_types are :auth_only, :capture_only

and :auth_capture
def create_transaction(amount, creditcard, transaction_type,
options = {})
#create_profile(creditcard, creditcard.gateway_options)
creditcard.save
if amount
amount = “%.2f” % (amount/100.0) # This gateway requires
formated decimal, not cents
end
transaction_options = {
:type => transaction_type,
:amount => amount,
:customer_profile_id =>
creditcard.gateway_customer_profile_id,
:customer_payment_profile_id =>
creditcard.gateway_payment_profile_id,
:order => {:invoice_number => @spree_invoice_number }
}.update(options)
#spree_invoice_number is nil here
logger.debug(“inside create_transaction:
#{transaction_options.inspect}\n” )
t = cim_gateway.create_customer_profile_transaction(:transaction
=> transaction_options)
logger.debug(“\nAuthorize Net CIM Transaction”)
logger.debug(" transaction_options:
#{transaction_options.inspect}“)
#spree_invoice_number is nil here also
logger.debug(” response: #{t.inspect}\n")
#instance variable is nil when can_access_instance_variable_here
called from this method:
can_access_instance_variable_here
t
end

# Create a new CIM customer profile ready to accept a payment
# now creates shipping address profile
def create_customer_profile(payment)
  options = options_for_create_customer_profile(payment)
  response = cim_gateway.create_customer_profile(options)
  if response.success?
    customer_profile_hash =
    { :customer_profile_id =>

response.params[“customer_profile_id”],
:customer_payment_profile_id =>
response.params[“customer_payment_profile_id_list”].values.first
}
return customer_profile_hash
else
payment.gateway_error(response) if
payment.respond_to? :gateway_error
payment.source.gateway_error(response)
end
end

def options_for_create_customer_profile(payment)
  if payment.is_a? Creditcard
    info = { :bill_to =>

generate_address_hash(payment.address), :payment => { :credit_card =>
payment }}
else
info = { :bill_to =>
generate_address_hash(payment.order.bill_address),
:payment => { :credit_card => payment.source } }
end
validation_mode = preferred_validate_on_profile_create ?
preferred_server.to_sym : :none

  { :profile => { :merchant_customer_id => "#{Time.now.to_f}",
                  #:ship_to_list =>

generate_address_hash(creditcard.checkout.ship_address),
:payment_profiles => info },
:validation_mode => validation_mode }
end

def cim_gateway
  ActiveMerchant::Billing::Base.gateway_mode =

preferred_server.to_sym
gateway_options = options

ActiveMerchant::Billing::AuthorizeNetCimGateway.new(gateway_options)
end

end

On Sun, Dec 11, 2011 at 1:16 AM, Cleverlemming [email protected]
wrote:

Hail Caesars!

I’m wondering why the instance variable “@spree_invoice_number” is out
of scope in both the authorize and the create_transaction methods in
the appended code. Both of the aforementioned methods are called after
the create_profile method, where the instance variable is
initialized. I checked to make sure the instance variable name is
unique in both the application and the gem repository.

Thanks in advance for any suggestions!

Can you show the caller code? From your description and the code,
everything looks good.
Can you try with a simpler version of your class:

class Gateway::AuthorizeNetCim < Gateway
attr_accessor :spree_invoice_number

def authorize(amount, creditcard, gateway_options)
logger.debug(“variable is: #{@spree_invoice_number}”)
end

def create_profile payment
@spree_invoice_number = 42
end
end

Jesus.

I think I have it figured out. It looks like there is more than one
instance of the Gateway::AuthorizeNetCim object involved, with the
caller method instantiating one of them to use the authorize instance
method like a class method (without relying on any instance
variables). This appears to be why my instance variable was out of
scope.

Tracking down the caller code was sound advice, thank you! I was
puzzled for a long time with this one.

Pete

-----caller method-----

def authorize(amount, payment)
# ActiveMerchant is configured to use cents so we need to multiply
order total by 100
payment_gateway = payment.payment_method
check_environment(payment_gateway)
logger.debug(“creditcard#authorize\n” )
response = payment_gateway.authorize((amount * 100).round, self,
gateway_options(payment))

On Dec 11, 3:55am, Jess Gabriel y Galn [email protected]