堆栈级别太深

时间:2014-04-03 23:43:28

标签: ruby-on-rails ruby-on-rails-4

您好我收到了#34;堆栈级别太深"错误,我很确定它是从这个模型生成的。我知道它与递归调用有关,但到目前为止我无法找到它,谢谢。

class Character < ActiveRecord::Base

  # Associations
  belongs_to :user

  # Validations
  validates :name, :presence => true, :uniqueness => true, :length => 
  { minimum: 2, maximum: 20 }, format: { with: /\A[a-zA-Z]+\Z/ }
  validates :race, :presence => true
  validates :class, :presence => true
  validates :user, :presence => true

  def self.races
    ["Human", "Dwarf", "Elven", "Orc", "Undead", "Demon"]
  end

  def self.classes
    {
      :fighter => {strength: 4, endurance: 3, dexterity: -2, charisma: -2, wisdom: -2, intelligence: -3}, 
      :thief   => {strength: -3,endurance: 2, dexterity: 4, charisma: 2, wisdom: -2, intelligence: 0}, 
      :magi    => {strength: -3, endurance: -2, dexterity: -2, charisma: 2, wisdom: 3, intelligence: -3}, 
      :ranger  => {strength: -2, endurance: 2, dexterity: 2, charisma: 0, wisdom: -3, intelligence: 0}, 
      :cleric  => {strength: 2,endurance: 2, dexterity: -3, charisma: -2, wisdom: 3, intelligence: 2}
    }
  end

  def set_class(_class)
    _attributes = Character.classes[_class.downcase]
    transaction do
      self.class = _class.downcase
      _attributes.each do |name, value|
        self.name += value
      end
      self.save
    end
  end
end

服务器日志:

Started GET "/characters/new" for 127.0.0.1 at 2014-04-04 01:54:14 +0200
  [1m[36mActiveRecord::SchemaMigration Load (0.8ms)[0m  [1mSELECT "schema_migrations".* FROM "schema_migrations"[0m
Processing by CharactersController#new as HTML
  [1m[35mUser Load (1.5ms)[0m  SELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1
  Rendered shared/_error_messages.html.erb (3.8ms)
  Rendered characters/new.html.erb within layouts/application (38.1ms)
Completed 500 Internal Server Error in 199ms

SystemStackError - 堆栈级别太深:

activerecord (4.0.2) lib/active_record/attribute_methods/read.rb:85:in `'

2 个答案:

答案 0 :(得分:5)

您的代码有三个问题:

  1. 您使用class作为属性
  2. 您感到困惑:symbols"String".downcase
  3. 您正在使用self.name(属性)认为它是一个不同的制定者。
  4. 请勿使用class。这是一个保留的关键字 这些线条会让ruby非常困惑:

    validates :class, :presence => true
    
    self.class = _class.downcase
    

    另外,我假设您的数据库表中有一个class列。您应该将其重命名为character_classrpg_class

    符号和字符串

    您的self.classes方法会返回一个Hash,其键是符号。然而,稍后您尝试使用字符串访问它:

    _attributes = Character.classes[_class.downcase]
    

    虽然:foobar.downcase无效,但您无法使用"Foobar".downcase访问这些值。
    要解决这个问题,您可以:

    无论如何,使用memoization可以改善该方法 目前,您正在为每次调用重新创建哈希哈希值。相反,您可以将其保存在变量中,并仅在第一次创建它。

    def self.classes
      @char_classes ||= { fighter: { #...
    end
    

    或者,更好的是,使用常数:

    CHAR_CLASSES = { #.....
    
    def self.classes
      CHAR_CLASSES
    end
    

    名称

    我看到您已经进行了此验证:

    validates :name, :presence => true, :uniqueness => true, :length => { minimum: 2, maximum: 20 }, format: { with: /\A[a-zA-Z]+\Z/ }
    

    这意味着您的数据库表中有一个name列,并且它应该是与特定格式匹配的String(仅限字母,介于2和20之间)。

    有了这个说,让我们来看看这段代码:

    _attributes.each do |name, value|
      self.name += value
    end
    

    在此本地范围内,name是一个包含Symbol(例如:strength)且valueFixnum的变量。 但是,当您执行self.name += value时,您要将Fixnum分配给对象属性 name

    我无法看到您定义strength=dexterity=等方法的位置。我假设他们是桌上的专栏。

    在这种情况下,这应该有效:

    self.public_send("#{name}=", value)
    # or just 'send' if it's a private method
    

答案 1 :(得分:2)

在角色上设置属性时,需要动态生成setter。您无法通过附加变量来调用动态方法。 name = 'mike'; self.name不会致电self.mike

def set_class(_class)
  _attributes = Character.classes[_class.downcase]
  transaction do
    self.class = _class.downcase
    _attributes.each do |name, value|
      self.public_send("#{name}=", value)
    end
    self.save
  end
end
相关问题