关于 rails 方式关系模型
About the rails way relation models
上下文:
我有两个 table,challenges
和 challenge_steps
。两个 table 之间都需要有关系,我需要能够引用 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
要做到这一点,我可以想到三个解决方案,但其中 none 个令人满意:
解决方案一:
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 文档显示:
For example, it makes more sense to say that a supplier owns an account than that an account owns a supplier.
所以行为没问题,但代码看起来很奇怪。
解决方案二:
创建一个包含 challenge_id
和 step_id
的 table。这将引用每个 challenge
及其 current_step
这个很好,但这意味着我们需要阅读另一个 table 以获得所需的信息。
方案三:
在Challenge
型号中加入:
has_many :steps, inverse_of: :challenge, dependent: :destroy do
def current_step
proxy_association.owner.steps.where(current_step: true).first
end
end
它 returns 集合和架构不尊重挑战与其步骤之间的真实关系。
什么最高效优雅?您能想出一个解决方案来解决 none 这些缺点吗?
我认为第一个解决方案是'The Rails Way'做你需要的。
也许唯一的缺点是代码可读性,从字面意义上讲,挑战不属于当前步骤,但我认为在线上的注释应该足够了,因为那时,界面访问它真的很有意义:challenge.current_step
首先,为什么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
模型中创建一个 current
列:
#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
模型中区分它。
上下文:
我有两个 table,challenges
和 challenge_steps
。两个 table 之间都需要有关系,我需要能够引用 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
要做到这一点,我可以想到三个解决方案,但其中 none 个令人满意:
解决方案一:
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 文档显示:
For example, it makes more sense to say that a supplier owns an account than that an account owns a supplier.
所以行为没问题,但代码看起来很奇怪。
解决方案二:
创建一个包含 challenge_id
和 step_id
的 table。这将引用每个 challenge
及其 current_step
这个很好,但这意味着我们需要阅读另一个 table 以获得所需的信息。
方案三:
在Challenge
型号中加入:
has_many :steps, inverse_of: :challenge, dependent: :destroy do
def current_step
proxy_association.owner.steps.where(current_step: true).first
end
end
它 returns 集合和架构不尊重挑战与其步骤之间的真实关系。
什么最高效优雅?您能想出一个解决方案来解决 none 这些缺点吗?
我认为第一个解决方案是'The Rails Way'做你需要的。
也许唯一的缺点是代码可读性,从字面意义上讲,挑战不属于当前步骤,但我认为在线上的注释应该足够了,因为那时,界面访问它真的很有意义:challenge.current_step
首先,为什么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
模型中创建一个 current
列:
#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
模型中区分它。