1

There are a couple of places where I could do what I need, but I'm not sure where the best place is in line with good practices.

I have an Orders controller, and after a successful order is created I want to create a subscription (but only if the order is a success), and a referral (but only if the order is associated with one).

Now the obvious choice is to use after_create on the Order model... but... how can I get session data into that? (The referral ids, friend ids and voucher ids are only in the session as there's no need to store them in the Order db).

So should I just create the Subscription and Referral objects in the create action (how I have it at the mo) or is there a better way?

Here's my create action: (@order.purchase only returns true if the payment was successful)

def create
if @order.save
    if @order.purchase
      Subscription.create(:order_id => @order.id, :product_id => @order.product_id)
      if @order.voucher
        Referral.create(:user_id => session[:friend_id], :order_id => @order.id, 
                        :voucher_amount => @voucher_value)
      end
      render :action => "success"
    else
      render :action => "failure"
    end
  else
    render :action => 'new'
  end
end

Any help would be appreciated - I really would like to do this properly so I hope no one minds me asking what is probably a simple question.

eBrooker
  • 49
  • 4

2 Answers2

0

use of callbacks will make your life easy, you need to use after_save

do all your stuff in after_save callback of order model. see rails api doc for callback here

Edit: If the session variable is not available with model, you can have a post_save method to deal with all logic which also accepts all require params like

like

class Order < ActiveRecord::Base
  def post_save require_attr

   #create subscriptions

   # create referral

  end
end 
Naren Sisodiya
  • 7,158
  • 2
  • 24
  • 35
  • Please look at what I'm trying to achieve - how do I get session data (and other variables) into my model for use with callbacks? – eBrooker Feb 29 '12 at 22:17
  • ok, didn't see that. in this case you can have a model method to do deal with all post create/save stuff and you can pass parameters to it. Basically all business logic should go to model, instead putting it in controller. – Naren Sisodiya Feb 29 '12 at 22:23
  • Ah right thanks lol, so I'm not using call-backs now, just normal methods in my model right? (Or am I missing some way on how to get parameters into the model for use with callbacks?). Thanks for your help! – eBrooker Feb 29 '12 at 22:40
  • I'm sorry I can't 'upvote' your answers as I don't have enough points or something. Anyway I went with a combination of your suggestions, moved everything into the model and used a virtual attribute to get my parameters across. Unfortunately I couldn't use callback methods as one of the attributes for creating a new object is only accessible after an update_attribute takes place, which is not called until after the Order is created (it's part of the .purchase method in my first post). Thank you both for your answers! – eBrooker Mar 01 '12 at 03:08
  • moving code to model is one step and using virtual attribute is good to hold variable required for other objects is also fine. I see you want to use order id, you can also achieve this by establishing association between Order product and referral and could use the association to create all those objects in after_save callback. – Naren Sisodiya Mar 01 '12 at 05:49
  • Hi Naren, I ended up using an Observer and virtual attribute as mentioned by SpyrosP. Thanks for you help! – eBrooker Mar 01 '12 at 19:31
0

I recently had a similar question, please take a look, i think that a simple virtual attribute in a callback will do it for you as well.

Fetch current user in after_create filter

Community
  • 1
  • 1
Spyros
  • 46,820
  • 25
  • 86
  • 129
  • Hi, thanks - virtual attributes seem like an interesting way to go about it. Are there any downsides to using them in this way? – eBrooker Feb 29 '12 at 23:17
  • I haven't had any really. It seems very natural and also allows you to use callbacks. – Spyros Mar 01 '12 at 01:47
  • I'm sorry I can't 'upvote' your answers as I don't have enough points or something. Anyway I went with a combination of your suggestions, moved everything into the model and used a virtual attribute to get my parameters across. Unfortunately I couldn't use callback methods as one of the attributes for creating a new object is only accessible after an update_attribute takes place, which is not called until after the Order is created (it's part of the .purchase method in my first post). Thank you both for your answers! – eBrooker Mar 01 '12 at 03:08
  • Don't worry about it :) You can try using the after_update callback instead. It's triggered everytime you save an existing record. – Spyros Mar 01 '12 at 03:19
  • Yeah, but I only need this to happen on the creation of a successful order. I could prob doing it by checking if the record has been updated within the last two minutes I guess, but still, think I'm ok the way I have it now. Thanks :) – eBrooker Mar 01 '12 at 03:32
  • So, if i understood correctly, you want to access an attribute after an update_attribute happens, but this update happens after your after_create callback on Order ? In that case, you can possibly create an observer. The core difference is that this one is able to observer more than one objects. Take a look here : http://stackoverflow.com/questions/3826260/rails-3-observer-looking-to-learn-how-to-implement-an-observer-for-multiple-m – Spyros Mar 01 '12 at 03:42
  • Yep that's it. I ended up creating an Observer on the OrderTransaction model as the other actions only really take place once an order transaction is marked as success. I also ended up using two virtual attributes, one for the order and one for the transaction. Thanks for your help! – eBrooker Mar 01 '12 at 19:29