Ruby on Rails Attribute Wrapper Design Pattern

I'm looking for the right way to implement the following in Ruby on Rails 5.1:

I have an ActiveRecord Platform with an attribute of structure_xml

type LONGTEXT. It contains pure XML. I would like to add a wrapper with helper methods to query XML (using Nokogiri) eg. find certain nodes or check it out.

My current solution

Non-ActiveRecord Model The framework implements the required methods:

def Structure   
  def initialize(xml)
    @xml_root = Nokogiri::XML(xml).root
  end

  def get_node_by_id(node_id)
    @xml_root.xpath(".//Node[@id='#{node_id}']").first
  end
  ...
end

      

The ActiveRecord model initializes this model as needed:

class Platform < ApplicationRecord
  attr_accessor :structure

  def structure
    @structure || (@structure = Structure.new(structure_xml))
  end
  ...
end

      

It works, but it doesn't seem perfect to me. What would be the correct approach to implement this?

+3


source to share


3 answers


You seem to be on the right track. I would do the same with a few minor changes:

class Platform < ApplicationRecord
  delegate :xml_root, :my_method1, :my_method2, to: :structure

  def structure
    @structure ||= Structure.new(structure_xml)
  end
  ...
end

      



delegate

allows you to invoke actions defined on another object without having to navigate through it.

You create modules only when you need a namespace, the same methods in more than one class, and when those methods are independent of the class object.

+1


source


I believe the Rails way would be to represent the DSL like this (not tested, but it should work out of the box):

module Structured
  def self.extended base
    base.send :define_method, :structure do
      @structure ||= {}
    end
  end
  def structured(*fields)
    fields.each do |field|
      define_method "#{field}_structure" do
        structure[field] ||= Structure.new(public_send field)
      end
    end
  end
end

      

somewhere in the initializers:



ApplicationRecord.extend Structured

      

and in yours Platform

(if it has a field data

containing the original xml):

class Platform < ApplicationRecord
  structured :data

  def print_it_out
    data_structure.get_node_by_id(3)
  end
end

      

+1


source


You might want to explore the Presenter or Decorator design pattern.

decorator

The decorator is similar to the inheritance functionality we find in many object-oriented programming languages. This allows you to add non-generic methods to define context objects that already have all the functionality of any generic object. As a Mercedes car brand, hold advanced facilities on top of typical car vehicles.

Presenter

The presenter is a type or a subset of the decorator itself. this is close to the MVC model. Presenters are composite objects, and we pass multiple options to it. This gives the desired result based on a successful state negotiation. The main goal of presenters is to bring logic out of the presentation.

At least I'm sure that's what you need, but the decorator pattern might also be what you're looking for, the links have some basic information about all of them.

0


source







All Articles