如何访问包含 belongs_to 2 个模型且所有 3 个模型都嵌套在另一个模型下的模型?

How to access a model that belongs_to 2 models with all 3 models nested under another model?

我正在对决策矩阵建模,因此对于每个 决策(其中的 n 个),有 x 备选方案 可供选择和 y 目标 达成。备选方案和目标的每个 x*y 对都有一个 Score 关联。

其他文档(在下面列出)已经解释了更简单的建模挑战,所以我仍然迷路了。我如何对决策矩阵建模并使用分数属性

下面是每个模型的代码片段和我尝试过的测试。

决定

class Decision < ActiveRecord::Base
  has_many :alternatives, dependent: :destroy
  has_many :goals, dependent: :destroy
  has_many :scores, dependent: :destroy
  validates :name, presence: true, length: { maximum: 50 }
end

备选方案

class Alternative < ActiveRecord::Base
  belongs_to :decision
  has_many :scores, dependent: :destroy
  validates :decision_id, presence: true
  validates :name, presence: true, length: { maximum: 50 }
end

目标

class Goal < ActiveRecord::Base

  belongs_to :decision
  has_many :scores, dependent: :destroy
  validates :decision_id, presence: true
  validates :name, presence: true, length: { maximum: 50 }
  validates :constraint, inclusion: [true, false]
  validates :rank, numericality: {only_integer: true,
                                    greater_than_or_equal_to: 1},
                                    allow_blank: true
  validates :weight, numericality: {greater_than_or_equal_to: 0,
                                    less_than_or_equal_to: 1},
                                    allow_blank: true
end

得分

class Score < ActiveRecord::Base
  belongs_to :decision
  belongs_to :goal
  belongs_to :alternative
  validates :decision_id, presence: true
  validates :goal_id, presence: true
  validates :alternative_id, presence: true
  validates :rating, numericality: {only_integer: true,
                                    greater_than_or_equal_to: -2,
                                    less_than_or_equal_to: 2},
                                    allow_blank: true
end

我在 decision_test.rb 中尝试了以下测试,但没有用,然后才意识到使用 Score 属性会有多么困难。

test "associated decision data should be destroyed" do
    @decision.save
    @alternative_1 = @decision.alternatives.create!(name: "toaster")
    @goal_1 = @decision.goals.create!(name: "fast")
    @score_1 = @decision.scores.build(
                    params[:score].merge(:alternative_id => @alternative_1.id,
                                         :goal_id => @goal_1.id)) ## doesn't work
    assert_difference ['Alternative.count','Goal.count'], -1 do
        @decision.destroy
    end
  end

Schema.rb

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

  create_table "alternatives", force: :cascade do |t|
    t.string   "name"
    t.integer  "decision_id"
    t.datetime "created_at",  null: false
    t.datetime "updated_at",  null: false
    t.decimal  "score"
  end

  add_index "alternatives", ["decision_id"], name: "index_alternatives_on_decision_id"

  create_table "decisions", force: :cascade do |t|
    t.string   "name"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "goals", force: :cascade do |t|
    t.string   "name"
    t.boolean  "constraint",  default: false
    t.integer  "rank"
    t.decimal  "weight"
    t.integer  "decision_id"
    t.datetime "created_at",                  null: false
    t.datetime "updated_at",                  null: false
  end

  add_index "goals", ["decision_id"], name: "index_goals_on_decision_id"

  create_table "scores", force: :cascade do |t|
    t.integer  "rating"
    t.decimal  "value"
    t.integer  "decision_id"
    t.integer  "goal_id"
    t.integer  "alternative_id"
    t.datetime "created_at",     null: false
    t.datetime "updated_at",     null: false
  end

  add_index "scores", ["alternative_id"], name: "index_scores_on_alternative_id"
  add_index "scores", ["decision_id"], name: "index_scores_on_decision_id"
  add_index "scores", ["goal_id"], name: "index_scores_on_goal_id"

end

资源(最相关的):

这可能是解决此问题的一种方法。

因为每个 Decision 有很多 Alternatives(x) 和很多 Goals (y),并且这些只是 X,Y 配对,这些配对应该存储为连接table。 Score 是这个连接 table,因为它本质上代表了一个 AlternativeGoal 类型的连接 table,只是它还存储了 X,Y 连接对的得分值。

要获得 link 评分的决定,您只需在设置 ID 时手动创建关系。我的直觉是 rails 将在关系创建后看到它。不理想(语法可能关闭)但我认为这可能有效:

决定:

has_many :alternatives, dependent: :destroy
has_many :goals, dependent: :destroy
has_many :scores, dependent: :destroy, class: Score

选择:

has_many :goals, through: :scores

目标:

has_many :alternatives, through: :scores

得分:

belongs_to :alternative
belongs_to :goal

那么你的执行将是这样的:

@decision.save
@alternative_1 = @decision.alternatives.create!(name: "toaster")
@goal_1 = @decision.goals.create!(name: "fast")
@score_1 = Score.new(alternative_id: @alternative_1.id, goal_id: @goal_1.id, score: params[:score], decision_id: @decision.id)
@score_1.save

那么@decision.scores应该可以了。

我倾向于同意 scores 模型并不像目前那样完全起作用。很难通过调用其他相关模型来创建它的实例。我会为您提出改进建议。

我相信 decisionalternativegoal 之间的关系以适当的方式建模。

我建议您将模型 score 与其他模型分开。 score class 应该不会 belong_to 其他机型。其他机型不要配置has_many :scores

schemar.rb 中的 table scores 可以在您拥有的状态下使用。

然后您可以在其他三个模型上创建一个 scores 函数,它会为您检索 score 模型,例如:

Decisions 模型中

def scores
  Score.where(decision_id:self.id)
end 

Alternatives 模型中

def scores
  Score.where(decision_id:self.decision.id,alternative_id:self.id)
end 

Goals 模型中

def scores
  Score.where(decision_id:self.decision.id,goal_id:self.id)
end 

这样可以单独配置包含评分系统 (scores) 的矩阵。