0

I have to process a very long form with multiple models.

def registerCandidate
    action_redirect = ""
    id = ""
    ActiveRecord::Base.transaction do
        begin

        @entity = Entity.new( name: params[:entity][:name], description: params[:entity][:description], logo: params[:entity][:logo])
        @access = Access.new( username: params[:access][:username], password: params[:access][:password], remember_me: params[:access][:rememberme], password_confirmation: params[:access][:password_confirmation])
        @access.entity = @entity
        @access.save!


        @biodata = Biodatum.new(
            date_of_birth: params[:biodatum][:birthday],
            height: params[:biodatum][:height],
            family_members: params[:biodatum][:family_members],
            gender: params[:biodatum][:gender],
            complexion: params[:biodatum][:complexion],
            marital_status: params[:biodatum][:marital_status],
            blood_type: params[:biodatum][:blood_type],
            religion: params[:biodatum][:religion],
            education: params[:biodatum][:education],
            career_experience: params[:biodatum][:career_experience],
            notable_accomplishments: params[:biodatum][:notable_accomplishments],
            emergency_contact: params[:biodatum][:emergency_contact],
            languages_spoken: params[:biodatum][:languages_spoken]
        )
        @biodata.entity = @entity
        @biodata.save!

        @employee = Employee.new()
        @employee.entity = @entity
        @employee.save!

        action_redirect = "success_candidate_registration"
        id = @access.id
        #action_redirect = "success_candidate_registration?id=" + @access.id

        #Error Processing
        rescue StandardError => e
          flash[:collective_errors] = "An error of type #{e.class} happened, message is #{e.message}"
          action_redirect = "candidate_registration"
      end
    end
    redirect_to action: action_redirect, access_id: id
  end

If I raise any error beyond @access.save! it does the entire transaction without rolling back. How do you modify in order for any error related to all models rollback everything?

max
  • 96,212
  • 14
  • 104
  • 165
james
  • 515
  • 4
  • 14

1 Answers1

0

Since you are rescuing StandardError - which most errors derive from you could very well be swallowing errors which could cause a rollback.

This is commonly known as Pokemon exception handling (Gotta catch em' all) and is an anti-pattern.

Instead listen for more specific errors such as ActiveRecord::RecordInvalid - and raise a raise ActiveRecord::Rollback on error to cause a rollback.

If you haven't already read the Active Record Transactions docs, there is some very good information there about what will cause a rollback.

Also if you want to be a good Ruby citizen and follow the principle of least surprise use snakecase (register_candidate) not camelCase (registerCandidate) when naming methods.

Added

Instead of copying every value from params to your models you should use strong parameters and pass the model a hash.

This reduces code duplication between controller actions and keeps your controllers nice and skinny.

class Biodatum < ActiveRecord::Base
  alias_attribute :date_of_birth, :birthday # allows you to take the :birthday param
end

# in your controller:
def register_candidate
   # ...
   @biodata = Biodatum.new(biodatum_params)
   # ...
end

private 

def biodatum_params
   params.require(:biodatum).allow(
    :birthday, :height, :family_members :family_members
   ) # @todo whitelist the rest of the parameters. 
end 
max
  • 96,212
  • 14
  • 104
  • 165