关于rails方式关系模型

时间:2015-09-18 15:17:03

标签: ruby-on-rails relationship models

上下文:

我有两个表,challengeschallenge_steps。两个表都需要有它们之间的关系,我需要能够引用Step Challenge和反向关系。

challenge可以有多个steps,但只有一个current_step

架构:

Challenge

t.string   "name"
t.string   "subtitle"
t.text     "brief",                     null: false
t.integer  "min_team_size", default: 2, null: false
t.integer  "max_team_size", default: 5, null: false
t.datetime "created_at",                null: false
t.datetime "updated_at",                null: false

Challenge::Step

t.integer  "challenge_id"
t.string   "name"
t.text     "description"
t.datetime "start_at"
t.datetime "end_at"
t.datetime "created_at",   null: false
t.datetime "updated_at",   null: false

要做到这一点,我可以想到三个解决方案,但它们都不令人满意:

解决方案一:

Challenge型号:

  has_many :steps, inverse_of: :challenge, dependent: :destroy
  belongs_to :current_step, class_name: Challenge::Step

Challenge::Step

  belongs_to :challenge
  has_one :challenge_relation, class_name: Challenge,
                               foreign_key: :current_step_id, dependent: :restrict_with_error

正如您在我的Challenge::Step模型中看到的,我有一个belongs_to(:challenge),Rails文档中写着:

  

例如,说供应商拥有的帐户比拥有供应商的帐户更有意义。

所以行为没问题,但代码看起来很奇怪。

解决方案二:

创建一个包含challenge_idstep_id的表格。其中将引用每个challenge及其current_step

这个很好,但这意味着我们需要读取另一个表来获取所需的信息。

解决方案三:

添加Challenge模型:

has_many :steps, inverse_of: :challenge, dependent: :destroy do
    def current_step
      proxy_association.owner.steps.where(current_step: true).first
    end
end

它返回一个集合,架构不尊重Challenge和他的步骤之间的真实关系。

最有效和优雅的是什么?你能想到一个没有这些缺点的解决方案吗?

2 个答案:

答案 0 :(得分:1)

首先,为什么Challenge::StepChallenge的子类?

当然你希望它自己是Step?为了清楚起见,我将其称为Step

-

这就是我要做的事情:

#app/models/challenge.rb
class Challenge < ActiveRecord::Base
    has_many :steps
    def current
        steps.where(current: true).order(current: :desc).first 
    end
end

#app/models/step.rb
class Step < ActiveRecord::Base
   # columns id | challenge_id | current (datetime) | etc...
   belongs_to :challenge
end

这将使您能够致电:

@challenge = Challenge.find params[:id]
# @challenge.steps = collection of steps
# @challenge.current_step = latest current step

您可以将current_step属性保存为Step模型中的日期。这将带来额外的好处,使您能够查看每个步骤何时“当前”的历史记录。

-

另一种方法是在current模型中创建Challenge列:

#app/models/challenge.rb
class Challenge < ActiveRecord::Base
   # columns id | name | current | etc
   has_many :steps
   def current_step
      steps.find current
   end
end

#app/models/step.rb
class Step < ActiveRecord::Base
   #columns id | challenge_id | name | etc
   belongs_to :challenge
end

这将允许您拨打以下电话:

@challenge = Challenge.find params[:id]
# @challenge.steps = collection of steps
# @challenge.current_step = single instance of step

-

您的第三个解决方案是迄今为止最优雅的解决方案,但它假设您实施的结构是正确的。

我认为您没有正确的设置来处理current_step属性;您需要一种方法来区分Step模型或Challenge模型。

答案 1 :(得分:0)

我认为第一个解决方案就是'The Rails Way'来做你需要的事情。

也许唯一的缺点是代码可读性,在某种意义上,挑战不属于字面上的当前步骤,但我认为对该行的评论应该足够,因为那时,访问的接口它真的很有意义:challenge.current_step

相关问题