Crysfel
Crysfel

Reputation: 8158

Transaction in rails 3

I would like to add the following code in a transaction to be able to rollback if there are errors in any of the inserts.

def create
    m = params[:message]

    # EmailThread.transaction do #<=== is this correct?
    if m[:parent_id].nil?
        thread = EmailThread.new :title => m[:subject]
        thread.save
    else
        thread = EmailThread.find m[:parent_id]
    end

    message = thread.messages.build :content => m[:content], :author_id => current_user.id
    message.save

    from = thread.participants.build :user_id => current_user.id
    to   = thread.participants.build :user_id => m[:to_user_id]

    from.save
    to.save

    #end  #<=== to here

    render :json => {:success=>true,:message=>"Message sent"}

end

I read that defining a transaction in a controller is not a good practice, can anyone help me solving this?

Regards

Upvotes: 0

Views: 123

Answers (2)

Leantraxxx
Leantraxxx

Reputation: 4606

I think Danny's answer is the correct one. But, If you need to do the transaction anyway the controller it's not the place to do it. You can create a method in your model to achieve this.

For example:

class Model < ActiveRecord::Base
  def self.some_method some_params
    Model.transaction do
      #do your stuff
      #return true if ok.
    end
  end
end

Then in your controller:

def create
  if Model.some_method #with the params you want to pass
     #render success
  else
     #render error
  end
end

Upvotes: 0

Danny
Danny

Reputation: 6025

As described in http://api.rubyonrails.org/classes/ActiveRecord/AutosaveAssociation.html, it is not necessary to explicitly save associations separately from their parents object.

In your case, as all objects created in your controller are "dependent", it is sufficient to first create all associations, using build, then finally save the parent object. This will automatically save all dependent associations.

Starting a transaction in a controller is only necessary when two or more totally independent, but somehow related, objects are created in the same action. The best example I can think of is a money transfer, with a debet and subsequent credit of two bank accounts. Both accounts are not "connected", but are very much dependent on each other: if one fails, the other should fail as well. That's when transactiond are the only solution!

Upvotes: 1

Related Questions