【问题标题】:How to access a model that belongs_to 2 models with all 3 models nested under another model?如何访问一个属于 2 个模型的模型,所有 3 个模型都嵌套在另一个模型下?
【发布时间】:2015-08-17 01:28:10
【问题描述】:

我正在建模一个决策矩阵,因此对于每个 Decision(其中 n 个),有 x 个 Alternatives 可供选择,y 个 Goals强>满足。备选方案和目标的每对 x*y 对都有一个关联的分数

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

下面是每个模型的代码sn-ps和我试过的一个测试。

决定

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

资源(最相关的):

【问题讨论】:

  • 您介意在您的问题中添加“scores”表的“schema.rb”创建脚本吗?
  • 您似乎想在这里使用多态关系、accepts_nested_attributes 形式的更新或涉及has_many ... :through 类型的语法。我们确实需要查看您的架构以了解您的目的,因为我怀疑您没有为此以一种好的方式构建您的数据结构。
  • 感谢@TheFabio。我已经在上面添加了。
  • @Kelseydh - 多态关系会保持得分与备选方案和目标的关联吗?
  • @purplengineer 您的目标、分数、决策和备选方案的架构在哪里?我在您的架构中没有看到这些表。

标签: ruby-on-rails matrix associations rails-models


【解决方案1】:

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

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

要让决策链接到分数,您只需在设置 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 应该可以工作了。

【讨论】:

  • 谢谢!我用您建议的模式替换了我的决策、目标、替代和分数模型,但它在我进行的所有 27 次测试中都失败了。也许我错过了一些东西,但决定撤消更改。在我原来的情况下,我尝试了直接输入参数(“rating”属性)的“@score_1 = Score.new(alternative_id: ......., rating: 0”行,我的测试通过了!
【解决方案2】:

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

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

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

schemar.rb 中的表 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) 的矩阵可以单独配置。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-28
    • 1970-01-01
    • 2013-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多