Thursday, January 26, 2006

Transactions

A number of my actions create objects of different models with some sort of association which are then saved in the database. To ensure data integrity, all the resulting SQL statements mustbe carried out, which basically means a transaction is needed.

Looking at the rails API though gave me a bit of a shock:


If you have multiple class-specific databases, the transaction will not protect interaction among them. One workaround is to begin a transaction on each class whose models you alter:

Student.transaction do
Course.transaction do
course.enroll(student)
student.units += course.units
end
end

This is a poor solution, but full distributed transactions are beyond the scope of Active Record


Thoughts about how my skills are not up to this task started to rise as I foresaw the corruption of clients data. I dug around a bit though and came up with the following, which also tidies up my code a bit:


def old_signup
@company = Company.new(@params[:company])
@user = User.new(@params[:user])
@address = Address.new(@params[:address])
@user.admin = true
@user.company = @company
@user.address = @address
if @request.post? and @user.valid? and @company.valid? and @address.valid?
@user.save
@company.save
@address.save
@company.addresses << @address
flash[:notice] = 'Signup successful'
redirect_to :action => 'welcome', :user => @user
else
flash.now[:notice] = 'Signup failed'
end
end

def new_signup
@user = User.new(@params[:user])
@user.admin = true
@user.company = Company.new(@params[:company])
@user.address = Address.new(@params[:address])
if @request.post? and @user.valid?
User.transaction do
@user.save
# return
@user.company.addresses << @user.address
end
flash[:notice] = 'Signup successful'
redirect_to :action => 'welcome', :user => @user
else
flash.now[:notice] = 'Signup failed'
end
end



I've tested it and it works; if 'return is uncommented, then the database is not altered. The only problem is that only the user is now validated. Hmmm.

0 Comments:

Post a Comment

<< Home