Note that there are some explanatory texts on larger screens.

plurals
  1. POSelecting Rails Models via Virtual Attributes
    primarykey
    data
    text
    <p>I have the two rails models <code>Section</code> &amp; <code>SectionRevision</code>. A Section is mostly just a container that holds all the Revisions relating to itself. So most of the attributes for the <code>Section</code> are basically stored within the <code>SectionRevision</code> model so there's a history of Revisions that can be reverted back to at any time.</p> <p>Sometimes I need to access the attributes for the latest revision from the Sections Model so I've created some Virtual Attributes to account for this.</p> <hr> <p>Each model has the attributes as defined in these migrations:</p> <p>Section:</p> <pre><code>class CreateSections &lt; ActiveRecord::Migration def change create_table :sections do |t| t.integer "page_id", :null =&gt; false t.timestamps t.datetime "deleted_at" end add_index("sections", "page_id") add_index("sections", "current_revision_id") end end </code></pre> <p>SectionRevision:</p> <pre><code>class CreateSectionRevisions &lt; ActiveRecord::Migration def change create_table :section_revisions do |t| t.integer "section_id", :null =&gt; false t.integer "parent_section_id" t.integer "position" t.string "title", :default =&gt; "", :null =&gt; false t.text "body", :null =&gt; false t.timestamps end add_index("section_revisions", "section_id") add_index("section_revisions", "parent_section_id") end end </code></pre> <hr> <p>And the models:</p> <p>SectionRevision:</p> <pre><code>class SectionRevision &lt; ActiveRecord::Base belongs_to :section, :class_name =&gt; 'Section', :foreign_key =&gt; 'section_id' belongs_to :parent_section, :class_name =&gt; 'Section', :foreign_key =&gt; 'parent_section_id' def parsed_json return JSON.parse(self.body) end end </code></pre> <p>Section:</p> <pre><code>class Section &lt; ActiveRecord::Base belongs_to :page has_many :revisions, :class_name =&gt; 'SectionRevision', :foreign_key =&gt; '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 =&gt; self.id) end end </code></pre> <hr> <p>As you can see <code>Section</code> has a couple of virtual attributes like, <code>parent_section</code>,<code>current_revision</code> &amp; <code>position</code>. </p> <p>The problem being now I would like to create a virtual attribute, <code>children</code> that selects all sections where the virtual attribute <code>parent_section.id</code> is equal to <code>self.id</code>. Is this possible at all? I know the above code won't work as its doing a query for a column that doesn't exist - and I'm not sure how to access the Model instances from within the model 'Sections' doesn't appear to work. </p> <p>Can a perform a selection based on virtual attributes?</p> <hr> <p>I've updated the model based on ProGNOMmers answer and get the following:</p> <pre><code>class Section &lt; ActiveRecord::Base has_many :revisions, :class_name =&gt; 'SectionRevision', :foreign_key =&gt; '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 =&gt; 'SectionRevision', :foreign_key =&gt; 'parent_section_id' has_many :children, :through =&gt; :child_revisions, :source =&gt; :section end </code></pre> <p>Circumstance 1: This works perfectly fine.</p> <pre><code>1.9.3p392 :040 &gt; section =&gt; #&lt;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&gt; 1.9.3p392 :041 &gt; sub_section =&gt; #&lt;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&gt; 1.9.3p392 :042 &gt; revision1 =&gt; #&lt;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&gt; 1.9.3p392 :043 &gt; revision2 =&gt; #&lt;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&gt; 1.9.3p392 :044 &gt; 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 =&gt; #&lt;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&gt; 1.9.3p392 :045 &gt; section.children =&gt; [#&lt;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&gt;] </code></pre> <p>Circumstance 2:</p> <pre><code>1.9.3p392 :021 &gt; section =&gt; #&lt;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&gt; 1.9.3p392 :022 &gt; sub_section =&gt; #&lt;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&gt; 1.9.3p392 :023 &gt; revision1 =&gt; #&lt;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&gt; 1.9.3p392 :024 &gt; revision2 =&gt; #&lt;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&gt; 1.9.3p392 :025 &gt; 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 =&gt; #&lt;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&gt; 1.9.3p392 :026 &gt; 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 =&gt; [#&lt;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&gt;] </code></pre> <p>In circumstance 2 I would like <code>section.children</code> to return <code>=&gt; []</code> as <code>sub_section.current_revision.parent_section_id = nil</code> and not <code>section.id</code>.</p> <p>In other words <code>section.children</code> should return all <code>Sections</code> where <code>.current_revision.parent_section_id = section.id</code> but I can't query that as <code>.current_revision</code> is a virtual attribute.</p> <p>Is it possible to maybe turn <code>Section.current_revision</code> in to some sort of association? Or maybe the only way is to add a <code>current_revision</code> column to the <code>sections table</code>?</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload