Topic: Access parent's private method fom associated belongs_to obect

Hello,

I have a setup based on the ActiveMerchant railscast (http://railscasts.com/episodes/145-inte … e-merchant)

One change from the railscast: A 'card_number' field is added to the order_transaction model to save the last 4 digits of a credit card for the transaction.

My goal is to save the ActiveMerchant::Billing.credit_card.display_number with order_transaction records.
(http://activemerchant.rubyforge.org/cla … ml#M000315)

The issue I'm running in to is where is the best place to set the order_transaction.card_number value?

There is a private 'credit_card' method in the order model but I'm not sure how I could access that information from a before_save callback.

# app/model/order.rb
class Order < ActiveRecord::Base
   ... 
   private 
   ...
  def credit_card
    @credit_card ||= ActiveMerchant::Billing::CreditCard.new(
      :type               => card_type,
      :number             => card_number,
      :verification_value => card_verification,
      :month              => card_expires_on.month,
      :year               => card_expires_on.year,
      :first_name         => first_name,
      :last_name          => last_name
    )
  end
  ...
end

Trying from the order_transaction model:

class OrderTransaction < ActiveRecord::Base
  ...

  before_save :set_cc   
 
  def set_cc 
    logger.info "testing"
    self.card_number = @reservation.credit_card.display_number
    #@reservation = Reservation.find(self.reservation_id)
    #@transaction.card_number = @credit_card.display_number
  end

end

Putting the before_save in order_transaction model does not appear to work. I don't seem to be able to access the parent @order object. I think I may be overlooking something fundamental...

I also tried putting the before save callback and method in the Order model. Since credit_card is a private method I get the error

private method `credit_card' called for #<Order:0xb5a34ef8>
class Order < ActiveRecord::Base
  ...
  before_save :set_cc   
 
  def set_cc
    logger.info "testing"
    # need to figure out proper way to access transactions from order model
    self.transactions[0].card_number = self.credit_card.display_number
  end
  ...

Some direction or suggestions appreciated. Thank you!

Last edited by internets (2012-03-26 08:49:08)

Re: Access parent's private method fom associated belongs_to obect

I'd put your method in the actual credit card model. 

def last4
  self.number.slice(self.number.length-4,4)
end

Then in your OrderTransaction model  you could do

def before_save
  self.card_number = self.credit_card.last4
end

Joe got a job, on the day shift, at the Utility Muffin Research Kitchen, arrogantly twisting the sterile canvas snout of a fully charged icing anointment utensil.

Re: Access parent's private method fom associated belongs_to obect

Thank you for the suggestion!

I think I got it worked out.

A much simpler solution seems to be just updating the Order model's purchase method to save the Transaction.

So I set up the the purchase method like so:

  def purchase
    response = OrderTransaction.gateway.purchase(price_in_cents, credit_card, purchase_options)
    t = transactions.create!(:action => "purchase", :amount => price_in_cents, :response => response)
    update_attribute(:reserved_at, Time.now) if response.success?
    t.card_number = credit_card.display_number
    t.save!
    response.success?
  end

Then in my views I can display the last 4 digits on a receipt like so:

  <% @order.transactions.each do |t| %>
-------------------------<br />
Date: <%= t.params["timestamp"].to_date.strftime('%m/%d/%Y') %><br />
Amount: <%= number_to_currency(t.params["amount"]) %><br />
Card Number: <%= t.card_number %><br /> 
-------------------------<br />
  <% end %>