我有两个表,challenges
和challenge_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_id
和step_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和他的步骤之间的真实关系。
最有效和优雅的是什么?你能想到一个没有这些缺点的解决方案吗?
答案 0 :(得分:1)
首先,为什么Challenge::Step
是Challenge
的子类?
当然你希望它自己是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