我有两个 Rails 模型 Section
和 SectionRevision
。 Section 通常只是一个容器,其中包含与其相关的所有 Revisions。因此,Section
的大部分属性基本上都存储在 SectionRevision
模型中,因此存在可以随时恢复的修订历史记录。
有时我需要从部分模型访问最新修订版的属性,因此我创建了一些虚拟属性来解决这个问题。
每个模型都具有这些迁移中定义的属性:
部分:
class CreateSections < ActiveRecord::Migration
def change
create_table :sections do |t|
t.integer "page_id", :null => false
t.timestamps
t.datetime "deleted_at"
end
add_index("sections", "page_id")
add_index("sections", "current_revision_id")
end
end
章节修订:
class CreateSectionRevisions < ActiveRecord::Migration
def change
create_table :section_revisions do |t|
t.integer "section_id", :null => false
t.integer "parent_section_id"
t.integer "position"
t.string "title", :default => "", :null => false
t.text "body", :null => false
t.timestamps
end
add_index("section_revisions", "section_id")
add_index("section_revisions", "parent_section_id")
end
end
和模型:
章节修订:
class SectionRevision < ActiveRecord::Base
belongs_to :section, :class_name => 'Section', :foreign_key => 'section_id'
belongs_to :parent_section, :class_name => 'Section', :foreign_key => 'parent_section_id'
def parsed_json
return JSON.parse(self.body)
end
end
部分:
class Section < ActiveRecord::Base
belongs_to :page
has_many :revisions, :class_name => 'SectionRevision', :foreign_key => 'section_id'
has_many :references
def current_revision
self.revisions.order('created_at DESC').first
end
def position
self.current_revision.position
end
def parent_section
self.current_revision.parent_section
end
def children
Sections.where(:parent_section => self.id)
end
end
如您所见,Section
有几个虚拟属性,例如 parent_section
、current_revision
和 position
。
现在的问题是我想创建一个虚拟属性 children
,它选择虚拟属性 parent_section.id
等于 self 的所有部分。编号
。这可能吗?我知道上面的代码不会工作,因为它对不存在的列进行查询 - 而且我不确定如何从模型“部分”中访问模型实例似乎不起作用。
能否根据虚拟属性进行选择?
我已经根据 ProGNOMmers 的回答更新了模型并得到以下信息:
class Section < ActiveRecord::Base
has_many :revisions, :class_name => 'SectionRevision',
:foreign_key => 'section_id'
#Need to somehow modify :child_revisions to only be selected if it is the section_id's current_revision?
has_many :child_revisions, :class_name => 'SectionRevision',
:foreign_key => 'parent_section_id'
has_many :children, :through => :child_revisions,
:source => :section
end
情况 1:这工作得很好。
1.9.3p392 :040 > section
=> #<Section id: 3, page_id: 10, created_at: "2013-04-02 01:31:42", updated_at: "2013-04-02 01:31:42", deleted_at: nil>
1.9.3p392 :041 > sub_section
=> #<Section id: 4, page_id: 10, created_at: "2013-04-04 10:19:33", updated_at: "2013-04-04 10:19:33", deleted_at: nil>
1.9.3p392 :042 > revision1
=> #<SectionRevision id: 5, section_id: 4, title: "test", body: "[{\"type\":\"testbody\"}]", created_at: "2013-04-04 10:21:46", updated_at: "2013-04-04 21:55:10", position: 3, parent_section_id: nil>
1.9.3p392 :043 > revision2
=> #<SectionRevision id: 6, section_id: 4, title: "test", body: "[{\"type\":\"testbody\"}]", created_at: "2013-04-04 12:29:19", updated_at: "2013-04-04 21:55:15", position: 3, parent_section_id: 3>
1.9.3p392 :044 > sub_section.current_revision
SectionRevision Load (0.6ms) SELECT `section_revisions`.* FROM `section_revisions` WHERE `section_revisions`.`section_id` = 4 ORDER BY created_at DESC LIMIT 1
=> #<SectionRevision id: 6, section_id: 4, title: "test", body: "[{\"type\":\"testbody\"}]", created_at: "2013-04-04 12:29:19", updated_at: "2013-04-04 21:55:15", position: 3, parent_section_id: 3>
1.9.3p392 :045 > section.children
=> [#<Section id: 4, page_id: 10, created_at: "2013-04-04 10:19:33", updated_at: "2013-04-04 10:19:33", deleted_at: nil>]
情况二:
1.9.3p392 :021 > section
=> #<Section id: 3, page_id: 10, created_at: "2013-04-02 01:31:42", updated_at: "2013-04-02 01:31:42", deleted_at: nil>
1.9.3p392 :022 > sub_section
=> #<Section id: 4, page_id: 10, created_at: "2013-04-04 10:19:33", updated_at: "2013-04-04 10:19:33", deleted_at: nil>
1.9.3p392 :023 > revision1
=> #<SectionRevision id: 5, section_id: 4, title: "test", body: "[{\"type\":\"testbody\"}]", created_at: "2013-04-04 10:21:46", updated_at: "2013-04-04 10:24:22", position: 3, parent_section_id: 3>
1.9.3p392 :024 > revision2
=> #<SectionRevision id: 6, section_id: 4, title: "test", body: "[{\"type\":\"testbody\"}]", created_at: "2013-04-04 12:29:19", updated_at: "2013-04-04 12:29:19", position: 3, parent_section_id: nil>
1.9.3p392 :025 > sub_section.current_revision
SectionRevision Load (0.7ms) SELECT `section_revisions`.* FROM `section_revisions` WHERE `section_revisions`.`section_id` = 4 ORDER BY created_at DESC LIMIT 1
=> #<SectionRevision id: 6, section_id: 4, title: "test", body: "[{\"type\":\"testbody\"}]", created_at: "2013-04-04 12:29:19", updated_at: "2013-04-04 12:29:19", position: 3, parent_section_id: nil>
1.9.3p392 :026 > section.children
Section Load (0.6ms) SELECT `sections`.* FROM `sections` INNER JOIN `section_revisions` ON `sections`.`id` = `section_revisions`.`section_id` WHERE `section_revisions`.`parent_section_id` = 3
=> [#<Section id: 4, page_id: 10, created_at: "2013-04-04 10:19:33", updated_at: "2013-04-04 10:19:33", deleted_at: nil>]
在情况 2 中,我希望 section.children
返回 => []
作为 sub_section.current_revision.parent_section_id = nil
而不是 section.id
.
换句话说,section.children
应该返回所有 Sections
,其中 .current_revision.parent_section_id = section.id
但我无法查询因为 .current_revision
是一个虚拟属性。
是否有可能将 Section.current_revision
变成某种关联?或者也许唯一的方法是将 current_revision
列添加到 sections 表
?
最佳答案
我认为自定义关系非常适合这种情况:
class Section < ActiveRecord::Base
has_many :revisions, :class_name => 'SectionRevision',
:foreign_key => 'section_id'
has_many :child_revisions, :class_name => 'SectionRevision',
:foreign_key => 'parent_section_id'
has_many :children, :through => :child_revisions,
:source => :section
end
Section.find(42).children
#=> SELECT ... WHERE ... AND section_revisions.parent_section = 42
代码我没试过,可能有错误,但思路应该是对的。
我删除了关于 :conditions
的部分,因为在上次编辑后没有用
关于ruby-on-rails - 通过虚拟属性选择 Rails 模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15805140/