Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 什么是「;轨道;执行一个有多个但只有一个当前关联的关联?_Ruby On Rails_Associations_Has Many - Fatal编程技术网

Ruby on rails 什么是「;轨道;执行一个有多个但只有一个当前关联的关联?

Ruby on rails 什么是「;轨道;执行一个有多个但只有一个当前关联的关联?,ruby-on-rails,associations,has-many,Ruby On Rails,Associations,Has Many,我有一个简单的rails应用程序,包含模型项目和阶段。一个项目有许多阶段,但一次只能有一个阶段处于活动状态(即“当前”)。我仍然希望其他阶段可以访问,但是当前阶段应该是应用程序的主锚。关于如何实现此需求的决策对我如何处理模型访问、验证和视图/表单以进行创建更新具有重大影响 所以问题是:如何在不增加太多复杂性的情况下实现“有很多但只有一个当前关联”?主要目标是:简化当前阶段的访问+确保一次不能有超过1个活动阶段。 当然,我自己也有一些想法,并提出了三个选择,我想在这里介绍。对于我为什么应该选择一个

我有一个简单的rails应用程序,包含模型项目和阶段。一个项目有许多阶段,但一次只能有一个阶段处于活动状态(即“当前”)。我仍然希望其他阶段可以访问,但是当前阶段应该是应用程序的主锚。关于如何实现此需求的决策对我如何处理模型访问、验证和视图/表单以进行创建更新具有重大影响

所以问题是:如何在不增加太多复杂性的情况下实现“有很多但只有一个当前关联”?主要目标是:简化当前阶段的访问+确保一次不能有超过1个活动阶段。

当然,我自己也有一些想法,并提出了三个选择,我想在这里介绍。对于我为什么应该选择一个选项而不是另一个选项(或建议更简单的解决方案),如有任何反馈,我将不胜感激:

第一个选项:

[Project] has_many :phases
[Project] has_one  :current_phase, :class_name => "Phase", :conditions => { :current => true }
[Project] has an attribute "current_phase_id"

[Project] has_many :phases
[Project] belongs_to phase, :foreign_key => "current_phase_id"
[Phase] has an attribute "active" (boolean)
[Phase] scope :active, :conditions => { :active => true}

# Access to current phase via: project.phases.active
缺点:我有一个用于创建项目和相应阶段的嵌套表单。似乎没有简单的方法可以精确地将新创建的一个阶段设置为活动阶段

第二选项:

[Project] has_many :phases
[Project] has_one  :current_phase, :class_name => "Phase", :conditions => { :current => true }
[Project] has an attribute "current_phase_id"

[Project] has_many :phases
[Project] belongs_to phase, :foreign_key => "current_phase_id"
[Phase] has an attribute "active" (boolean)
[Phase] scope :active, :conditions => { :active => true}

# Access to current phase via: project.phases.active
缺点:与选项1相同,但我有另一个属性,a属于关联,这看起来很奇怪(为什么一个项目应该属于它的一个阶段?)

第三个选项:

[Project] has_many :phases
[Project] has_one  :current_phase, :class_name => "Phase", :conditions => { :current => true }
[Project] has an attribute "current_phase_id"

[Project] has_many :phases
[Project] belongs_to phase, :foreign_key => "current_phase_id"
[Phase] has an attribute "active" (boolean)
[Phase] scope :active, :conditions => { :active => true}

# Access to current phase via: project.phases.active
缺点:我必须通过验证确保一次只有一个活动阶段,如果同时创建/编辑多个阶段或在从一个阶段切换到另一个阶段的过程中创建/编辑多个阶段,这是很困难的;另外:如果我没有弄错的话,project.phases.active将返回一个数组

非常感谢你的帮助。谢谢

更新
增加了一笔奖金,以鼓励对该主题发表进一步的意见。奖励将授予最能实现上述主要目标的解决方案;或者,如果没有提到替代解决方案,那么答案最好地解释了为什么我应该选择其中一个选项而不是另一个。谢谢

一个提出得很好的问题。我一直在为类似的事情挣扎。我得到的结果与您的选项1类似,但使用了联接表

class Project < ActiveRecord::Base
has_many :phases, :through=> :project_phase

has_one :active_project_phase, :class_name => 'ProjectPhase'`
class项目:项目\u阶段
有一个:活动的项目阶段,:class\u name=>'ProjectPhase'`

为了准确地设置一个新创建的阶段处于活动状态,我在控制器中有一些代码,使它们都处于非活动状态,然后如果没有阶段,则添加一个新的活动阶段,或者根据传入的参数和一系列规则选择一个活动阶段。虽然不漂亮,但它很管用。我确实先尝试了选项3,但由于您描述的原因,我发现它变得非常混乱。选项1看起来非常自然。您只需添加验证来验证是否只有一个阶段具有
current
标志和
project\u id
以及一些javascript来控制客户端的复选框

class Project < AR::Base
  has_many :phases
  has_one  :current_phase, :class_name => "Phase", :conditions => { :current => true }
  accepts_nested_attributes_for :phases, :allow_destroy => true
end

class Phase < AR::Base
  belongs_to :project
  validates :project_id, :uniqueness => {:scope => :current}, :if => proc{ self.current }
end

为什么不在
阶段
模型中添加一个名为
activated_at
的日期时间列呢。然后将其设置为当前时间,只要您想激活某个阶段

在任何给定的时间,最新的
激活值为
的阶段都是当前阶段,因此您可以通过
@project.phases.order('activated_At DESC')获得它。首先
。只需将其包装在
Project
中的一个方法中,就可以得到一个非常简洁的表示:

# in project.rb
def current_phase
  phases.where("activated_at is NOT NULL").order('activated_at DESC').first
end

只要重新阅读我的答案,并意识到它实际上是你的选择1-重写它!呵呵,谢谢你的想法。我没有想到在这里使用联接表,所以您的答案肯定有助于找到可能的解决方案+1美元。仍然期待看到其他意见。我会改进一点:
phases.where(“activated\u at is NOT NULL”)。order(“activated\u at DESC”)。首先,其次。非常感谢你,edgerunner@FLRR:巨大的改进——我很高兴看到你们在这里的共同努力导致了我现在认为的“最佳实践”:您也可以将
激活的\u at
列设为必填列,但任何一种方法都有效,并且至少必须执行一项操作。如果我们同时创建三个新阶段,必填字段将弄乱它。在Rails 6中,我相信您现在可以执行类似
阶段的操作。where.not(激活的\u at:nil)。order(激活的\u at::desc).首先
非常感谢fl00r-我感谢您为详细答案和javascript位所做的努力(尽管我将尝试通过单选按钮解决此问题-不幸的是,使用rails表单帮助程序并不容易…)。由于edgerunner解决方案的简单性,我将奖励他正确的答案。我同意@edgerunner解决方案更好。我更喜欢选项2,它看起来很奇怪,我同意,但你不需要额外的验证来检查电流的唯一性,也不需要更新数据库中的两条记录来更改电流。谢谢你的反馈,@ryaz。我选择了下面埃德格朗纳的得票最高的答案。更加优雅,易于操作。