web-dev-qa-db-fra.com

Erreur de niveau de pile trop profonde dans Ruby on Rails

J'ai une erreur de niveau de pile trop profonde en utilisant Ruby 1.8.7 avec Rails 3.0.4 et avec le Rails = console J'ai exécuté les commandes suivantes.

leo%>Rails console
Loading development environment (Rails 3.0.4)
Ruby-1.8.7-head > leo = Organization.find(1)

SystemStackError: stack level too deep
from /app/models/organization.rb:105:in `parents'

Voici l'objet qui a des problèmes ..

class Organization < ActiveRecord::Base

  has_many                  :group_organizations, :dependent =>
:delete_all
  has_many                  :groups, :through => :group_organizations

  has_many                  :orders
  has_many                  :product_contracts

  has_many                  :people
  accepts_nested_attributes_for :people

  has_many                  :addresses
  accepts_nested_attributes_for :addresses

  has_many                  :organizations
  has_many                  :departments
  has_many                  :organization_credits

  has_many                  :documents

  validates_presence_of     :name



    def self.parents
      @organizations = Organization.where("is_company = ?",true)
      #@organization_parents = []
      select_choice = I18n.t("select") + " "+ I18n.t("segments.description")
      @organization_parents = [select_choice]
      for organization in @organizations
        @organization_parents << [organization.name, organization.id]
      end
      return @organization_parents
    end
25
Leo

J'ai trouvé la solution à ce problème ...

J'utilise Rails 3 et ma classe ressemble à ceci (et les méthodes problématiques l'étaient aussi)

class Organization < ActiveRecord::Base
  def self.parents
    @organizations = self.find :all, :conditions => ['is_company = ? ',true]
    select_choice = I18n.t("select") + " "+ I18n.t("segments.description")
    @organization_parents = [select_choice]
    for organization in @organizations
      @organization_parents << [organization.name, organization.id]
    end
    return @organization_parents
  end 
  #...
end

J'ai dû pirater beaucoup dans le code pour découvrir que quelque chose n'allait pas avec le named_scope sur la ligne

@organizations = self.find :all, :conditions => ['is_company = ? ',true]

J'ai donc dû le changer en quelque chose comme ça

@organizations = Organization.where("is_company = ?",true)

Mais c'était faux aussi .. J'ai donc décidé d'ajouter une portée pour cela sous le nom de la classe pour que le code final ressemble à ceci:

class Organization < ActiveRecord::Base
  scope :company, where("is_company = ?",true)

  def self.parents
    @organizations = self.company
    select_choice = I18n.t("select") + " "+ I18n.t("segments.description")
    @organization_parents = [select_choice]
    for organization in @organizations
      @organization_parents << [organization.name, organization.id]
    end
    return @organization_parents
  end 
  #...
end

Donc, en utilisant cette ligne avec la portée

@organizations = self.company

cela a fonctionné parfaitement dans chaque partie du code.

Je me demandais si le named_scope est obsolète lors de l'utilisation de méthodes de classe ou s'ils ne sont pas pris en charge à partir de maintenant et génère une erreur et pas un avertissement avant

Merci pour votre aide Leo

1
Leo

Cette erreur se produit généralement lorsque vous modifiez accidentellement et récursivement un attribut. Si vous avez un attribut de nom d'utilisateur dans le modèle utilisateur et un attribut virtuel nommé nom d'utilisateur, qui modifie directement le nom d'utilisateur, vous finissez par appeler le virtuel, le virtuel appelle à nouveau le virtuel et ainsi de suite. Par conséquent, vérifiez si quelque chose comme ça arrive quelque part dans votre code.

52
Spyros

L'erreur niveau de pile trop profond se produit également si vous voulez détruire un enregistrement et que vous avez une association avec :dependent => :destroy vers un autre modèle. Si l'autre modèle est associé à :dependent => :destroy de retour à ce modèle, le le niveau de la pile est trop profond, aussi.

19
Christian

J'ai eu un "stack-level too deep" problème aussi. cela était dû à la récursivité de l'une de mes fonctions et avait été causé par une faute de frappe comme vous pouvez le voir ci-dessous:

def has_password?(submitted_password)
  encrypt_password == encrypt(submitted_password)
end

private

def encrypt_password
  self.salt = make_salt unless has_password?(password)
  self.encrypted_password = encrypt(password)
end

J'ai réalisé que je devais changer la deuxième ligne en crypté et cela a fonctionné. Vérifiez simplement la récursivité dans votre code, cela doit se produire quelque part. Malheureusement, je ne peux pas être mieux utilisé car je ne peux pas regarder tous vos fichiers de code.

4
Lym

J'obtenais la même chose niveau de pile trop profond erreur et il s'avère que le problème était le rendu récurrent d'un partiel.

Il m'est arrivé d'appeler render a_partial dans la vue principale, puis dans le partiel, j'ai accidentellement appelé à nouveau le même partiel.

HTH

3
Pradeep S

Si vous obtenez cette erreur, cela signifie Rails que vous utilisez dans votre application n'est pas compatible avec la version Ruby Version.

Solutions que vous pouvez utiliser pour résoudre ce problème.

1) Vous devez rétrograder la version Ruby vers une version plus ancienne).

2) ou vous devez mettre à niveau Rails vers la dernière version.

2
Hitesh Ranaut

Comme vous ne montrez pas tout le code, je ne peux que spéculer que vous avez défini inspect ou to_s pour construire une chaîne contenant, entre autres, les parents.

Votre méthode parents actuelle ne semble pas faire quoi que ce soit de raisonnable, car elle renvoie toutes les organisations qui sont des entreprises, quelle que soit l'association à partir de laquelle vous commencez. Ainsi, toute entreprise a elle-même comme société mère. Tenter de le convertir en chaîne induira une boucle infinie pour essayer de montrer les parents des parents de ...

Dans tous les cas, la majeure partie de votre méthode parents doit être dans un assistant, appelé quelque chose comme options_for_parents_select, parce que c'est ce qu'il semble faire? Même alors, le premier choix vide doit être passé comme allow_null pour sélectionner.

Le fait qu'il définit des variables d'instance est une odeur de code.

Bonne chance

2