【问题标题】:Ruby on Rails 4.2, stack level too deep, associations and delegate()Ruby on Rails 4.2,堆栈级别太深,关联和委托()
【发布时间】:2017-07-04 10:20:16
【问题描述】:

我了解Stack Level Too Deep 错误的原因。我无法发现它在我的代码库中出现的位置/原因。

我已经实现了一个多模型、多步骤的向导。前两个模型(UserCompany)正在工作,当我尝试添加第三个模型(Address)时,我得到了错误。

我怀疑错误与模型之间的关联有关,尽管我未能调试。

下面的代码 sn-ps 正常运行,除非我在文件 app/wizards/user_wizard/step1.rb 中添加 3 行(在 sn-p 中用 cmets 标记)。。 p>

相关模型

app/models/company.rb

class Company < ActiveRecord::Base
  include Validatable::Company

  # Associations:
  has_many :addresses, inverse_of: :company
  accepts_nested_attributes_for :addresses, reject_if: :all_blank

  has_many :employees, inverse_of: :company
  accepts_nested_attributes_for :employees, reject_if: :all_blank

  has_many :licenses, inverse_of: :company
  accepts_nested_attributes_for :licenses, reject_if: :all_blank

  has_many :vehicles, inverse_of: :company
  accepts_nested_attributes_for :vehicles, reject_if: :all_blank

  has_one :user, inverse_of: :company
end

app/models/address.rb

class Address < ActiveRecord::Base
  # Associations:
  belongs_to :company, inverse_of: :addresses

  has_many :licenses, inverse_of: :address
  accepts_nested_attributes_for :licenses, reject_if: :all_blank

  has_many :initial_analyses, inverse_of: :address
  accepts_nested_attributes_for :initial_analyses, reject_if: :all_blank
end

app/models/user.rb

class User < ActiveRecord::Base
  include SoftDeletable
  include Validatable::User

  # Constants:
  MARKER_ATTRIBUTES = %w[user_name].freeze # get marked with '(deleted)'
  DEPENDANT_CHILDREN = %w[none].freeze # child resources to be deleted

  # Associations:
  belongs_to :role, inverse_of: :users

  belongs_to :company, inverse_of: :user
  accepts_nested_attributes_for :company, reject_if: :all_blank

  has_many :auto_quotes, inverse_of: :user
end

db/schema.rb

ActiveRecord::Schema.define(version: 20170616131833) do

  create_table "addresses", force: :cascade do |t|
    t.integer  "company_id"
    t.text     "site_name"
    t.string   "premises_code"
    t.string   "exempt_premises_code"
    t.text     "address"
    t.string   "city"
    t.string   "county"
    t.string   "sic_code"
    t.string   "postcode"
    t.string   "country"
    t.boolean  "sic_update"
    t.boolean  "deleted",              default: false
    t.datetime "created_at",                           null: false
    t.datetime "updated_at",                           null: false
    t.datetime "deleted_at"
  end

  create_table "companies", force: :cascade do |t|
    t.string   "company_name"
    t.string   "registration_number"
    t.string   "type_of_business"
    t.datetime "created_at",          null: false
    t.datetime "updated_at",          null: false
    t.datetime "deleted_at"
  end

  create_table "users", force: :cascade do |t|
    t.string   "email",                  default: "", null: false
    t.string   "encrypted_password",     default: "", null: false
    t.string   "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.integer  "sign_in_count",          default: 0,  null: false
    t.datetime "current_sign_in_at"
    t.datetime "last_sign_in_at"
    t.string   "current_sign_in_ip"
    t.string   "last_sign_in_ip"
    t.string   "confirmation_token"
    t.datetime "confirmed_at"
    t.datetime "confirmation_sent_at"
    t.string   "unconfirmed_email"
    t.integer  "failed_attempts",        default: 0,  null: false
    t.string   "unlock_token"
    t.datetime "locked_at"
    t.datetime "created_at",                          null: false
    t.datetime "updated_at",                          null: false
    t.string   "user_name"
    t.datetime "deleted_at"
    t.integer  "role_id"
    t.integer  "company_id"
    t.string   "invitation_token"
    t.datetime "invitation_created_at"
    t.datetime "invitation_sent_at"
    t.datetime "invitation_accepted_at"
    t.integer  "invitation_limit"
    t.integer  "invited_by_id"
    t.string   "invited_by_type"
    t.integer  "invitations_count",      default: 0
  end

  add_index "users", ["company_id"], name: "index_users_on_company_id", unique: true
  add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
  add_index "users", ["email"], name: "index_users_on_email", unique: true
  add_index "users", ["invitation_token"], name: "index_users_on_invitation_token", unique: true
  add_index "users", ["invitations_count"], name: "index_users_on_invitations_count"
  add_index "users", ["invited_by_id"], name: "index_users_on_invited_by_id"
  add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
  add_index "users", ["unlock_token"], name: "index_users_on_unlock_token", unique: true
end

向导

app/wizards/user_wizard/base.rb

module UserWizard
  class Base
    include ActiveModel::Model

    STEPS = %w[step1 step2].freeze

    attr_accessor :user

    delegate(*::User.attribute_names.map {|attr| [attr, "#{attr}="] }.flatten, to: :user)

    def initialize(user_attributes)
      @user = ::User.new(user_attributes)
    end
  end
end

app/wizards/user_wizard/step1.rb

module UserWizard
  class Step1 < UserWizard::Base
    include Validatable::Company

    attr_accessor :company

    # One of 3 lines triggering circular reference by adding in Address model
    attr_accessor :address

    delegate(*::Company.attribute_names.map {|attr| [attr, "#{attr}="] }.flatten, to: :company)

    # One of 3 lines triggering circular reference by adding in Address model
    delegate(*::Address.attribute_names.map {|attr| [attr, "#{attr}="] }.flatten, to: :address)

    def initialize(user_attributes)
      super

      @company = @user.build_company

      # One of 3 lines triggering circular reference by adding in Address model
      @address = @user.company.addresses.build
    end
  end
end

app/wizards/user_wizard/step2.rb

省略,因为它无关紧要。代码在实例化此类之前失败

【问题讨论】:

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


    【解决方案1】:

    address 有一个address 属性。所以委托方法试图创建一个方法address,它将被委托给address

    我建议这样做:

    module UserWizard
      class Step1 < UserWizard::Base
        include Validatable::Company
    
        attr_accessor :company
    
        # One of 3 lines triggering circular reference by adding in Address model
        attr_accessor :company_address
    
        delegate(*::Company.attribute_names.map {|attr| [attr, "#{attr}="] }.flatten, to: :company)
    
        # One of 3 lines triggering circular reference by adding in Address model
        delegate(*::Address.attribute_names.map {|attr| [attr, "#{attr}="] }.flatten, to: :company_address)
    
        def initialize(user_attributes)
          super
    
          @company = @user.build_company
    
          # One of 3 lines triggering circular reference by adding in Address model
          @company_address = @user.company.addresses.build
        end
      end
    end
    

    【讨论】:

    • 感谢 ReggieB 找到了我找不到的东西。我喜欢编程,但是找不到明显的答案是令人沮丧的!哈哈。生活和学习
    • 显而易见的是最难发现的 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-09
    • 1970-01-01
    • 2015-05-15
    • 1970-01-01
    • 2017-05-21
    • 2012-07-24
    • 1970-01-01
    相关资源
    最近更新 更多