Reputation: 348
I am looking for the right way to implement the following in Ruby on Rails 5.1:
I have an ActiveRecord Platform with the attribute structure_xml
of type LONGTEXT. It contains pure XML. I would like to add a wrapper with helper methods to query the XML (using Nokogiri), e.g. to find certain nodes or to validate it.
My current solution
A non-ActiveRecord model Structure 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 initialises this model if needed:
class Platform < ApplicationRecord
attr_accessor :structure
def structure
@structure || (@structure = Structure.new(structure_xml))
end
...
end
It works, but it does not seem ideal to me. What would be the right approach to implement this?
Upvotes: 3
Views: 1624
Reputation: 16002
You seem to be on right path. I would do probably the same with slight 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 call the actions defined in another object without having to navigate through it.
You create modules only when you require namespace, same methods in more than one class, and when those methods are independent of an object of a class.
Upvotes: 1
Reputation: 121000
I believe, Rails way would be to introduce a DSL like that (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 initializers:
ApplicationRecord.extend Structured
and in your Platform
(assuming it has a field data
containing the raw xml):
class Platform < ApplicationRecord
structured :data
def print_it_out
data_structure.get_node_by_id(3)
end
end
Upvotes: 1
Reputation: 2929
You might want to look into the Presenter or Decorator design pattern.
Decorator
A decorator resembles functionality of inheritance that we find in many object oriented programming languages. It allows adding of non-generic methods to define contextual objects which already possess all features of any common entity. Like Mercedes brand’s motorcars hold advance facilities on top of typical automobile machines.
Presenter
A presenter is a type or subset of decorator itself. It is close to view model of MVC architecture. Presenters are composite objects and we feed multiple options to it. It renders desired outcome based on successful matching of condition. The main objective of presenters is to put logic out of the view.
At least I'm pretty sure that's what you need but the decorator pattern might also be what you're looking for, the links has some basic info on both of them.
Upvotes: 0