4

我有两个导轨模型Section& SectionRevision。一个部分主要是一个容器,其中包含与其自身相关的所有修订。因此,大多数属性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.id。这可能吗?我知道上面的代码不起作用,因为它对不存在的列进行查询 - 而且我不确定如何从模型“Sections”中访问 Model 实例似乎不起作用。

可以根据虚拟属性进行选择吗?


我已经根据 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>] 

情况2:

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返回=> []assub_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_revisionsections table?

4

2 回答 2

3

我认为自定义关系非常适合这种情况:

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,因为在最后一次编辑后没有用

于 2013-04-04T08:00:16.760 回答
2

看起来你应该像 ProGNOMmers 所说的那样改进你的模型;您可以使用以下一些宝石:

但是从字面上回答您的问题,您可以尝试将“children”方法添加到您的 SectionRevision 模型并将 Section#children 委托给 current_revision。

class SectionRevision
  def children
    SectionRevision.where(:parent_section => self.id) # parent_section IS a column of SectionRevision
  end
end

class Section
  def children
    current_revision.children
  end
end

顺便说一句,您可以使用 #delegate 进行委派:

class Section
  delegate :children, :position, :parent_section, to: :current_revision
  def current_revision
    Section.where(:parent_section => self.id)
  end
end

http://apidock.com/rails/Module/delegate

于 2013-04-04T08:21:22.313 回答