MarkdownRecord Docs

Custom Models and Associations

This sectional will discuss how to create MarkdownContent models and defines associations on them, as well as how to define associations between MarkdownContent and ActiveRecord models.

To make a MarkdownContent, it only needs to inherit from MarkdownContent::Base. Once you have done that, you can define attributes and associations on it to other MarkdownContent models.

Attributes

MarkdownContent::Base includes ActiveAttr::Model to provide attribute functionality. Please see how to use the ActiveAttr gem's interface here.

Asscociations

You can define custom associations on your model using the belongs_to_content, has_one_content and has_many_content methods like so:

module MarkdownRecord
  module Demo
    class Section < ::MarkdownRecord::Base
      attribute :name
      has_many_content :dsl_commands
    end
  end
end
module MarkdownRecord
  module Demo
    class DslCommand < ::MarkdownRecord::Base
      attribute :name
      attribute :description
      belongs_to_content :section
    end
  end
end

Once the associations are defined, you will want to make sure your JSON objects in your markdown have the required fields. For the example above, the DslCommand model will automatically be given a section_id field that will need to be populated in your markdown like so:

<!--model { "type": "dsl_command", "id": 6, "name": "directory_fragment", "section_id": 1 } -->

Then you can use the association in your code just like ActiveRecord associations:

Section.find(3).dsl_commands.all
 => 
[#<DslCommand section_id: 1, description: "...", ...>, ...]
DslCommand.find(1).section
 => #<Section filename: "content_dsl", id: 3, name: "Content DSL", subdirectory: "content", type: "section">

has_many_content will define a method that returns an MarkdownRecord::Association object, which you can then chain queries onto. belongs_to_content and has_one_content will define methods that returns a single MarkdownContent model.

Scopes

If a model is defined within a scope (using the scope Content DSL command), then all its associations are assumed to be within that scope, and must point to other models that are within that scope.

Furthermore, when querying for models that are defined within a scope without using associations, you will need to provide the scope like so:

DslCommand.find(1, "v_0_1_3")
 => #<DslCommand description: "model is the main command...", scope: "v_0_1_3", scoped_id: "v_0_1_3:s:1", section_id: 3, subdirectory: "content", type: "dsl_command"> 

Or

DslCommand.where(:section_id => 3, :scope => "v_0_1_3").all
 => [#<DslCommand >,...]

Association methods do not need the scope provided, since they are assumed to be in the same scope as the model instance you call them on.

Associations on ActiveRecord Models

You can easily integrate MarkdownRecord and ActiveRecord models together using the MarkdownRecord::ContentAssociations module. Just include it in your ActiveRecord model like so:

class Product < ActiveRecord::Base
  include MarkdownRecord::ContentAssociations
  has_one_content :user_manual
  has_many_content :research_notes
end

You can define the same associations as described for MarkdownRecord models for ActiveRecord models. An important difference between the two cases, however, is that there are no foreign keys on the MarkdownRecord models that point to ActiveRecord models. Instead, MarkdownRecord expects to find an attribute on the ActiveRecord model that can be used for querying the MarkdownRecord models. For example, the Product model above should have a user_manual_id column or attribute. This effectively makes has_one_content and belongs_to_content aliases for each other. In the case of has_many_content, the model should have an attribute that is a JSON array of ids that point to the related MarkdownRecord models. In the example above, it would be called research_note_ids.

The above content was rendered from source files at: content/v_0_1/custom_models_and_associations