stack level too deep on creation

For some reason I'm getting stack level too deep on my group#create, and I can't recall making any changes before it started showing this error.

class GroupsController < ApplicationController

 def new
  @group = current_user.company.groups.new
 end

 def create
    @group = current_user.company.groups.new(group_params)
    if @group.save
      flash[:success] = 'saved'
      redirect_to groups_path
    else
      render 'new'
    end
  end

  private

  def group_params
    params.require(:group).permit(:name, user_ids: [])
  end
end



class Group < ActiveRecord::Base
  belongs_to :company

  has_many :group_memberships
  has_many :users, through: :group_memberships
  # questions
  has_many :question_participants, as: :questionable
  has_many :questions, through: :question_participants

  accepts_nested_attributes_for :group_memberships

  validates :name, presence: true, length: { maximum: 255 }
end

and group_memberships:

class GroupMembership < ActiveRecord::Base
  belongs_to :group
  belongs_to :user
  validates :user_id, uniqueness: { scope: :group_id }
end

and user:

# User model
class User < ActiveRecord::Base
  belongs_to :company
  # groups
  has_many :group_memberships
  has_many :group_questions, through: :groups, source: :questions
  has_many :groups, through: :group_memberships

form:

<%= form_for @group do |f| %>

    <%= f.label :name %>
    <%= f.text_field :name, class: 'form-control', autofocus: true %>

    <%= f.label :user_ids %>
    <%= f.collection_select :user_ids, User.order(:first_name), :id, :first_name, {},
      { multiple: true } %>


  <%= f.submit class: 'btn btn-primary' %>
<% end %>

it happens when I submit, irrelevant if there's any data there or not.

Started POST "/groups" for ::1 at 2015-10-23 09:37:08 +0200
Processing by GroupsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"5OCDQ27Aepg4ptjJdj9TF5kZkNcqE2GjnEh3OqH6gftOKLp+uIeLI3KDycImSM4WvUIRELghyVdqhURy7tLsWg==", "group"=>{"name"=>"", "user_ids"=>[""]}, "commit"=>"create"}
  User Load (0.3ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1  [["id", 1]]
  Company Load (0.3ms)  SELECT  "companies".* FROM "companies" WHERE "companies"."id" = $1 LIMIT 1  [["id", 1]]
Completed 500 Internal Server Error in 9ms (ActiveRecord: 0.7ms)

SystemStackError - stack level too deep:
  newrelic_rpm (3.14.0.305) lib/new_relic/agent/instrumentation/middleware_tracing.rb:89:in `'

my controller:

Upvotes: 1

Views: 877

Answers (4)

I finally found a solution, after almost 9 hours straight working on debugging this. I'll try to write this detailed so people in a similar situation can fix this asap, because this is one hell of a bug to fix.

The issue was a problem with my bullet gem. If you have 'gem bullet' to look for N+1 then removing it and the initializer worked for me.

However if you don't have this / or if you do and you want to see how I figured out that it was the problem what I did was:

  1. Create a new file called trace.rb in your config/initializer/
  2. Insert this code into it:

-

$enable_tracing = false
#$trace_out = File.open(Rails.root + 'trace.txt', 'w')

set_trace_func proc { |event, file, line, id, binding, classname|
  if $enable_tracing && event == 'call'
    #$trace_out.puts "#{file}:#{line} #{classname}##{id}"
    raise "crash me" if caller_locations.length > 500
  end
}

$enable_tracing = true

now re-run (and remember to restart your rails server because it's an initializer file) the place where you get the issue, and it will loop over the problem. In my case I got this:

  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'
  bullet (4.14.9) lib/bullet/active_record42.rb:194:in `has_cached_counter?'

and for there I was able to use reason and understand that the problem was with bullet. However as seen in my question I had absolutely no error message displaying and no way of telling that this was the issue.

Hope this works for future people!

Upvotes: 0

Richard Peck
Richard Peck

Reputation: 76784

stack level too deep basically means infinite loop


You've got an infinitely recursive loop in your groups#create method somewhere; I'd surmise - like the others - that it's do with current_user.company.groups...

#app/models/company.rb
class Company < ActiveRecord::Base
  belongs_to :user
  has_many :groups
end

#app/models/group.rb
class Group < ActiveRecord::Base
  belongs_to :company

  has_many :memberships
  has_many :users, through: :memberships
end

#app/models/membership.rb
class Membership < ActiveRecord::Base
  belongs_to :group
  belongs_to :user
end

I think the problem is that you're calling groups on a company belonging to a particular user, which Rails will automatically assume to have a user attribute too. IE it will call find groups where id = [company_id] and user_id = [user_id]

If you want to create a group on a company, you don't have to use current_user (I think this is what's causing the problem):

def create
    company = Company.find_by id: current_user.id
    @group  = company.groups.new group_params
    if @group.save
      flash[:success] = 'saved'
      redirect_to groups_path
    else
      render 'new'
    end
end

This is not correct (it will be best to call current_user.company), but it will remove the user element from your call.

I think that because you're allowing the addition of users to groups, and calling current_user, Rails is getting might confused.

If you try the above code it should work


Anyway, it's bad practice (law of demeter) to have many different "connections" on a single object. It translates simply into you shouldn't have more than one "dot" in your calls:

current_user.groups

You generally get around this by using alias_attribute, but that's another story :)


Update

Some observations after looking at your repo:

#app/models/user.rb
class User < ActiveRecord::Base
   has_one :company
   has_and_belongs_to_many :groups
end

#app/models/group.rb
class Group < ActiveRecord::Base
   belongs_to :company
   has_and_belongs_to_many :users
end

#app/models/company.rb
class Company < ActiveRecord::Base
    belongs_to :owner, class_name: "User", foreign_key: :user_id
    has_many :groups #-> group.users.each
end

-

#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
    before_filter :company

    private

    def company
       current_user.company
    end
end

#app/controllers/groups_controller.rb
class GroupsController < ApplicationController
   def index
      @groups = company.groups.all
   end

   def new
      @users = User.where.not(id: current_user.id).order(:first_name)
      @group = company.groups.new
   end

   def create
      @group = company.groups.new group_params
      @group.save
   end
end

This should allow you to populate the group with users as follows:

#app/views/groups/new.html.erb
<%= form_for @group do |f| %>
   <%= f.text_field :name %>
   <%= f.collection_select :user_ids, @users, :id, :first_name %>
   <%= f.submit %>
<% end %>

Upvotes: 1

Moustafa Sallam
Moustafa Sallam

Reputation: 1132

The problem coming from the many-to-many polymorphic relationship with questions and you should indicate that the group has_many users as shown below:

Update the group.rb as the following:

class Group < ActiveRecord::Base
  belongs_to :company

  has_many :group_memberships
  has_many :users, through: :group_memberships
  # questions
  has_many :question_participants, as: :questionable
  has_many :questions, through: :question_participants, as: :questionable

  accepts_nested_attributes_for :group_memberships

  validates :name, presence: true, length: { maximum: 255 }
end

Upvotes: 0

Prashant4224
Prashant4224

Reputation: 1601

Please modify the model like:

user.rb

class User < ActiveRecord::Base
  has_many :groups, through: :group_memberships
  has_many :group_memberships
end

group.rb

class Group < ActiveRecord::Base
  belongs_to :company

  has_many :group_memberships
  # questions
  has_many :question_participants, as: :questionable
  has_many :questions, through: :question_participants

  accepts_nested_attributes_for :group_memberships

  validates :name, presence: true, length: { maximum: 255 }
end

group_membership.rb

class GroupMemberhip < ActiveRecord::Base
  belongs_to :user
  belongs_to :group
end

Upvotes: 2

Related Questions