复杂嵌套has_many / has_one关联

时间:2019-06-28 22:51:16

标签: ruby-on-rails activerecord

我的模型很复杂,因此我将首先询问以下问题和详细信息。我有一些交叉模型关联。我想我说对了,但我无法使用“直通”关联进行备份。

示例:

Expenditure.first.budget => OK
ExpenditureItem.first.expenditure.budget => OK
ExpenditureItem.first.project => OK

ExpenditureItem.first.budget => FAIL:

ExpenditureItem Load (0.5ms)  SELECT "expenditure_items".* FROM "expenditure_items" ORDER BY "expenditure_items"."id" ASC LIMIT $1  [["LIMIT", 1]]
NoMethodError: undefined method `klass' for nil:NilClass
from /Users/aximus/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0.rc1/lib/active_record/reflection.rb:790:in `source_reflection'

我不明白的是,为什么当Budget属于Project时,为什么'ExpenditureItem.first.project'可以工作,但是'ExpenditureItem.first.budget'却失败了?

我曾考虑在此处添加一些其他直接外键,但认为这样做可以。我现在可以添加它们(budget_id和budget_code_id),但希望避免添加。我也可以在模型中添加方法。

我希望这里缺少一些琐碎的事情,或者有人可以告诉我,我无法使用ActiveRecord做到这一点。

我还有另一层“客户”,“预算代码”和“项目”属于该层,但我认为这是一个非常复杂的问题。

问题:为什么我的模型关联无法按预期工作?


这是我的模型的简要概述

class BudgetCode < ApplicationRecord

  has_many :budget_code_items
  has_many :projects

class BudgetCodeItem < ApplicationRecord

  belongs_to :budget_code

所以它看起来像这样:

预算代码1

  1. DevOps
  2. 发展
  3. 测试
  4. UI / UX

然后您创建一个预算:

class Budget < ApplicationRecord

  belongs_to :project
  belongs_to :budget_code

  has_many :budget_items
  has_many :expenditure_items, through: :budget_code_item
  has_many :expenditures, through: :expenditure_item

class BudgetItem < ApplicationRecord

  belongs_to :budget_code_item
  belongs_to :budget

myapp预算(预算1)

  1. DevOps:$ 1,000
  2. 发展$ 2,000
  3. 测试$ 100
  4. UI / UX 10,000美元

然后我有该预算的支出:

class Expenditure < ApplicationRecord

  belongs_to :vendor
  belongs_to :budget

  has_one :budget_code, through: :budget
  has_one :project, through: :budget
  has_one :client, through: :project

  has_many :budget_items, through: :budget
  has_many :expenditure_items

class ExpenditureItem < ApplicationRecord

  before_save :calculate_amount

  belongs_to :budget_code_item
  belongs_to :expenditure

  has_one :budget_code, through: :budget_code_item
  has_one :budget, through: :expenditure
  has_one :project, through: :budget

更新

这是我的相关架构。我掏出了所有的绒毛-这说明了这种关系。

  create_table "budget_code_items", force: :cascade do |t|
    t.bigint "budget_code_id", null: false
    t.index ["budget_code_id"], name: "index_budget_code_items_on_budget_code_id"
  end

  create_table "budget_codes", force: :cascade do |t|
    t.bigint "client_id", null: false
    t.index ["client_id"], name: "index_budget_codes_on_client_id"
  end

  create_table "budget_items", force: :cascade do |t|
    t.bigint "budget_code_item_id", null: false
    t.bigint "budget_id", null: false
    t.index ["budget_code_item_id"], name: "index_budget_items_on_budget_code_item_id"
    t.index ["budget_id"], name: "index_budget_items_on_budget_id"
  end

  create_table "budgets", force: :cascade do |t|
    t.bigint "project_id", null: false
    t.bigint "budget_code_id", null: false
    t.index ["budget_code_id"], name: "index_budgets_on_budget_code_id"
    t.index ["project_id"], name: "index_budgets_on_project_id"
  end

  create_table "expenditure_items", force: :cascade do |t|
    t.bigint "budget_code_item_id", null: false
    t.index ["budget_code_item_id"], name: "index_expenditure_items_on_budget_code_item_id"
    t.index ["expenditure_id"], name: "index_expenditure_items_on_expenditure_id"
  end

  create_table "expenditures", force: :cascade do |t|
    t.bigint "budget_id", null: false
    t.boolean "flag_active", default: true
    t.index ["budget_id"], name: "index_expenditures_on_budget_id"
  end

0 个答案:

没有答案