ruby-on-rails - 通过虚拟属性选择 Rails 模型

标签 ruby-on-rails ruby model attributes virtual-attribute

我有两个 Rails 模型 SectionSectionRevision。 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_sectioncurrent_revisionposition

现在的问题是我想创建一个虚拟属性 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/

相关文章:

ruby-on-rails - asset_host Rails 3 在哪里?

c++ - 将 Z3 整数表达式转换为 C/C++ int

javascript - 在本地主机上模拟加载

ruby-on-rails - Ajax 请求在多次成功请求后停止工作

ruby watirrecorder 的 Python 替代品?

ruby - ElasticSearch的 "MoreLikeThis"查询如何使用Tire

swift - Realm 和 Swift - 为要更新的模型传递的参数

mysql - 使用 Propel ORM 从 Symfony 中的现有数据库错误生成模型

ruby-on-rails - 与设计/cancan 不同的注册过程但只有一个用户模型?

irb 中的 Ruby 字符串比较和字符编码