我的模型很复杂,因此我将首先询问以下问题和详细信息。我有一些交叉模型关联。我想我说对了,但我无法使用“直通”关联进行备份。
示例:
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
然后您创建一个预算:
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)
然后我有该预算的支出:
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