我有一个jobs
表和一个activities
表。一个工作可以有很多活动。这种关系是多态的。
表:
job activities
----------- -------------
id id
... target_id
target_type
...
模型伪代码:
class Job < ActiveRecord::Base
# ...
has_many :activities, :as => :target, :dependent => :delete_all
# ...
end
class Activity < ActiveRecord::Base
# ...
belongs_to :target, :polymorphic => true
# ...
end
给定作业的状态由与其相关的最后一个活动的状态决定,如下所示(本例中的最后一个是最后创建的,因此我们可以按ID安全地排序)。
Job +-> Activity 1 - state: new |
+-> Activity 2 - state: submitted +--> Job state is approved
`-> Activity 3 - state: approved |
如何使用ActiveRecord和Rails 3/4仅查询给定状态的作业?
我(我)也想到了这样一个想法,即完全不使用这个查询,而是使用像“计数器缓存”这样的用法并对关系进行非规范化。我会将状态存储在作业表上并使用after_create
模型上的Activity
挂钩保持同步状态?这方面的事情:
after_create :update_state
def update_state
target.update_attribute(state: self.state) if target.respond_to?(:state)
end
这会以一种更简单的方式解决问题吗?
答案 0 :(得分:0)
我不认为这里的多态性会成为一个问题(它只是一种选择正确数据的方法)
状态机
怎么样?从外观上看,你的模型过度设计了。您的Job
有州,而不是activity
,那么为什么使用其他型号会造成复杂化?
如果使用状态机,则本机处理对象的状态,如下所示:
#app/models/job.rb
Class Job < ActiveRecord::Base
state_machine :initial => :new do
#States
state :new
state :submitted
state :approved
### Events ###
#Submit
event :submit do
transition :new => :submitted
end
#Approve
event :approve do
transition :submitted => :approved
end
end
end
这将直接在您的作业模型中使用Job
属性处理state
状态
最重要的方面是使用state-machine
events:
#State Machine Functions
@job = Job.find(id)
@job.state #-> "new"
@job.new? #-> false
@job.submitted? #-> false
@job.approved? #-> true
@job.submit! #-> state: "new" -> "submitted"
@job.approve! #-> state: "submitted" -> "approved"
<强>作用域强>
如果您不想删除activity
模型,则可能希望使用scopes
代替
虽然我知道你可以使用它,但我不确定多态关联的语法是否正确:
#app/models/job.rb
Class Job < ActiveRecord::Base
scope :submitted, -> { joins(:activity).where(state: "submitted") }
scope :activity, ->(activity = new) { joins(:activity).where(state: activity) }
end