Skip to content

Instantly share code, notes, and snippets.

@inopinatus
Last active July 20, 2017 22:42
Show Gist options
  • Save inopinatus/11bf7deedb5a813d3e75e0cf63db863a to your computer and use it in GitHub Desktop.
Save inopinatus/11bf7deedb5a813d3e75e0cf63db863a to your computer and use it in GitHub Desktop.
Rails model templates, concept sketch
require "active_record"
require "sqlite3"
require "minitest/autorun"
require "logger"
require "pp"
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Schema.define do
create_table :devices, force: true do |t|
t.string :name
t.string :model
t.string :location
t.integer :year
end
create_table :interfaces, force: true do |t|
t.integer :device_id
t.string :name
t.string :address
t.boolean :enabled
end
create_table :templates, force: true do |t|
t.string :name
t.string :klass
t.text :template
end
end
class Template < ActiveRecord::Base
def self.make!(object, name: default_name(object))
create!(name: name, klass: object.class.to_s, template: object.as_template.to_json)
end
def use(&block)
klass.constantize.from_template(JSON.parse(template), &block)
end
private
def self.default_name(object)
"New #{object.model_name.singular} template"
end
end
class Device < ActiveRecord::Base
has_many :interfaces
def self.from_template(template, &block)
if template.is_a?(Array)
template.map { |tpl| from_template(tpl, &block) }
else
object = new(template.slice("model", "location", "year"), &block)
object.interfaces << Interface.from_template(template["interfaces"])
object
end
end
def as_template
{
"model" => model,
"location" => location,
"year" => year,
"interfaces" => interfaces.map(&:as_template)
}
end
end
class Interface < ActiveRecord::Base
belongs_to :device
def self.from_template(template, &block)
if template.is_a?(Array)
template.map { |tpl| from_template(tpl, &block) }
else
object = new(template.slice("name", "address", "enabled"), &block)
object
end
end
def as_template
{
"name" => name,
"address" => address,
"enabled" => enabled
}
end
end
class TemplateTest < Minitest::Test
def test_template_stuff
device = Device.create!(name: "router", model: "CX-6790", location: "SFO", year: 2017)
device.interfaces << Interface.create!([{name: "de0", address: "10.0.0.1", enabled: false}, {name: "lo0", address: "127.0.0.1", enabled: true}])
Template.make!(device, name: 'SFO router template')
new_device = Template.last.use do |dev|
dev.name = "router-2"
end
new_device.save!
assert_equal 1, Template.count
assert_equal 2, Device.count
assert_equal 2, new_device.interfaces.count
assert_equal new_device.id, Interface.last.device.id
pp new_device.as_json(include: :interfaces)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment