ActiveRecord::Base.transaction - SystemStackError - stack level too deep:

704 views
Skip to first unread message

Bob O

unread,
Jun 22, 2013, 7:06:54 PM6/22/13
to rubyonra...@googlegroups.com
Im having an issue that seems to only happen when trying to use a transaction. Ive used transactions many times in the past and Im at a loss as to why im getting the stack level too deep problem.

SystemStackError - stack level too deep:
  actionpack (3.2.13) lib/action_dispatch/middleware/reloader.rb:70:in `'

I have a StackOveflow with more detail - http://stackoverflow.com/q/16930511/1408461

As stated in the SO. If I try to save the record to the database outside the transaction it saves just fine. I only get the error in the transaction. 

Params Object

params => {
  "resource"=> {
    "resource_type"=>"document", 
    "resource_name"=>"My Rails Doc",
    "source_id"=>"Dropbox"
  },
  "resource_document"=> {
    "resource_document"=> #<ActionDispatch::Http::UploadedFile:0x007f8e919d06f8
      @content_type="text/plain",
      @headers= "Content-Disposition: 
        form-data; name=\"resource_document[resource_document]\";
        filename=\"rails_local_env_setup.txt\"\r\n
        Content-Type: text/plain\r\n",
      @original_filename="rails_local_env_setup.txt",
      @tempfile= #<File:/var/folders/t4/lfmj7mhj52b2krryzh7dj4hh0000gn/T/RackMultipart20130604-29589-2c0seo>>},

  "action"=>"create",
  "controller"=>"resources"
 }
**Controller**
def create

  if current_teacher
    @resource = ResourceObject.create_teacher_resource(params, current_teacher)
  end

  if current_student
    @resource = ResourceObject.create_student_resource(params, current_student)
  end

  if current_admin
    @resource = Resource.new(params[:resource])
  end

  respond_to do |format|
    if @resource.success
      format.html { redirect_to @resource, notice: 'Resource was successfully created.' }
      format.json { render json: @resource, status: :created, location: @resource }
    else
      format.html { render action: "new" }
      format.json { render json: @resource.errors, status: :unprocessable_entity }
    end
  end
end
**Transaction**
class ResourceObject

  def self.create_teacher_resource(params, teacher)
    begin
      ActiveRecord::Base.transaction do
        # Create Resource
        @resource = Resource.new
        @resource.resource_name = params[:resource][:resource_name]
        @resource.resource_type = params[:resource][:resource_type]
        @resource.source_id = params[:resource][:source_id]
        @resource.teacher_id = teacher.id
        @resource.save

        # Create Resource Document
        @resource_document = ResourceDocument.new
        @resource_document.resource_document = params[:resource_document][:resource_document]
        @resource_document.resource_id = @resource.id
        @resource_document.save

        # TODO Add Commom Core Joins
        # TODO Video Uploader
        # TODO Image Uploader

        return @resource.success = "ok"
      end
        rescue Exception => e
      # TODO Need to figure out how to pass exception message back to controller
          return @resource.errors
        end     
      end
    end
end
Resource Model

class Resource < ActiveRecord::Base include TransactionAttributes attr_accessible :resource_name, :resource_type, :source_id, :teacher_id, :student_id, :success, :errors belongs_to :teacher, :class_name => "Teacher", :foreign_key => "teacher_id" belongs_to :student, :class_name => "Student", :foreign_key => "student_id" has_many :resource_documents # has_many :resource_images # has_many :resource_videos # has_many :question_resources # has_many :assignment_resources end

Matt Jones

unread,
Jun 23, 2013, 9:25:08 PM6/23/13
to rubyonra...@googlegroups.com
A style note here: rescuing Exception is not typically what you want. See this for more details:

 

      # TODO Need to figure out how to pass exception message back to controller
          return @resource.errors
        end     
      end
    end
end
Resource Model

class Resource < ActiveRecord::Base include TransactionAttributes

I'd be curious as to what's in this module - it could be relevant...
 
attr_accessible :resource_name, :resource_type, :source_id, :teacher_id, :student_id, :success, :errors

 :errors here is not useful - attr_accessible controls mass-assignment of attributes (as when you do Resource.new(:param1 => 'foo', :param2 => 'bar'). You almost certainly do not want to mass-assign an internal part of ActiveRecord. :)

belongs_to :teacher, :class_name => "Teacher", :foreign_key => "teacher_id" belongs_to :student, :class_name => "Student", :foreign_key => "student_id"

Another minor (not terribly relevant) style note: :class_name and :foreign_key are both redundant here, as the values specified are the same as the ActiveRecord defaults. 

Next steps for debugging this:

- it would be useful to see the code for the TransactionAttributes module you're including. Perhaps something is hitting an internal method and making a mess.

- showing the DB schema would help as well; again, having fields with names that clash with ActiveRecord's can cause peculiar behavior.

- a full stack trace might shed some light; especially in the case of StackLevelTooDeep, the final line isn't always helpful.

--Matt Jones

Bob O

unread,
Jun 23, 2013, 11:22:26 PM6/23/13
to rubyonra...@googlegroups.com
This is the TransactionAttributes

module TransactionAttributes

  def success
    success
  end

  def success=(success)
    self.success = success
  end

  def errors
  errors
  end

  def errors=(errors)
  self.errors = errors
  end
end

The reason for these was i was trying to set a property on a returned object or the errors. I yet to figure out a way i can return a more descriptive error message from the transaction back to the controller. 

I'll fix the style note. That just happens to populate when using a tab trigger in Sublime.

This is the table schema

# == Schema Information
#
# Table name: resources
#
#  id            :integer          not null, primary key
#  resource_name :string(255)
#  teacher_id    :integer
#  student_id    :integer
#  source_id     :string(255)
#  created_at    :datetime         not null
#  updated_at    :datetime         not null
#  resource_type :string(255)
#

The SystemStackError - stack level too deep:
  actionpack (3.2.13) lib/action_dispatch/middleware/reloader.rb:70:in `' 
is the only thing i get in the console.

This is whats returned in the response.

SystemStackError at /resources
==============================

> stack level too deep

actionpack (3.2.13) lib/action_dispatch/middleware/reloader.rb, line 70
-----------------------------------------------------------------------

``` ruby
65 response = @app.call(env)
66 response[2] = ActionDispatch::BodyProxy.new(response[2]) { cleanup! }
67 response
68 rescue Exception
69 cleanup!
> 70 raise
71 end
72
73 def prepare! #:nodoc:
74 run_callbacks :prepare if validated?
75 end
```

App backtrace
-------------



Full backtrace
--------------

- actionpack (3.2.13) lib/action_dispatch/middleware/reloader.rb:70:in `'


based on a SO i read it said to turn on the Rails.backtrace_cleaner.remove_silencers!

so ive dont that.

Is there something else i can do to that would be helpful?

Matt Jones

unread,
Jun 24, 2013, 2:27:44 PM6/24/13
to rubyonra...@googlegroups.com


On Sunday, 23 June 2013 20:22:26 UTC-7, Bob O wrote:
This is the TransactionAttributes

module TransactionAttributes

  def success
    success
  end

  def success=(success)
    self.success = success
  end

That's the problem right there - this method is calling itself. If you want to define a getter / setter, you should either do this:

def success
  @success
end

def success=(value)
  @success = value
end

---
Or this (preferred, if you're just storing a value, as above):

attr_accessor :success

 
  def errors
  errors
  end

  def errors=(errors)
  self.errors = errors
  end
end

These will break some things - ActiveRecord already defines an `errors` method + `errors=` assignment operator, and expects them to behave in a particular way (for instance, the validations assume that you can make calls like `some_model.errors.add(:some_attribute, 'message')`).

I highly recommend reading through the guides (http://guides.rubyonrails.org/) or following some of Michael Hartl's excellent tutorial (http://ruby.railstutorial.org/) in preference to digging through Stack Overflow - the answers there are incredibly useful if you've got a highly specific problem, but they can sometimes miss the bigger picture.

Hope this helps,

--Matt Jones

Bob O

unread,
Jun 24, 2013, 10:33:44 PM6/24/13
to rubyonra...@googlegroups.com
Thanks Matt. That was the problem. At one point I had pulled those out, or at least I thought I did. I guess thats why I was confused. Anyway. Thanks For the help. I do have Michaels stuff. Its very good. My setters were a rookie mistake. 

One thing that I wish i could find more stuff about is transactions. Most examples seem to handle the transactions in the controller which I dont like. So I have troubles getting the errors back to the controller for better user feedback. Hence the reason I was trying to use the TransactionAttributes module. Backfire!

Appreciate your help.

Bob


On Saturday, June 22, 2013 5:06:54 PM UTC-6, Bob O wrote:
Reply all
Reply to author
Forward
0 new messages