0

I'm developing a model which holds configuration settings for server options. The number and type of server options change, and I need some input on the pros/cons of two ways of doing it. I'm doing this separate from the rails ActiveRecord database. All my database interactions are going to be manually with the file system.

First, having the model dynamically create attributes as needed for each server specified. (as long as this is possible... I've never done it before)

Second, creating a single Hash, which has Keys of the server options, and values of the server settings.

I think the second would be easier to implement, but I'm not sure if it is the right way to go? It seems to be cleaner to go with dynamic attributes.

Is there a rule of thumb to go with for this?

Josh Johnson
  • 563
  • 3
  • 11
  • 29

2 Answers2

4

Do you know about the Store functionality in Rails?

http://api.rubyonrails.org/classes/ActiveRecord/Store.html

Basically you could write something like this:

class Server < ActiveRecord::Base
  store :options
end

You need to create a new migration as well with an options column and type text.

Now you can add and read values to the 'options' store like so:

server_instance.options[:ip] = '10.0.1.7'
server_instance.options[:ip] # returns the IP.

You can also clean this up by adding an accessors option to the store call.

class Server < ActiveRecord::Base
  store :options, accessors: [ :ip, :port ]
end

Now you can use ip & port as regular attributes.

server_instance.ip = '10.0.1.7'
server_instance.ip # returns the IP.
SpoBo
  • 2,100
  • 2
  • 20
  • 28
  • I forgot to mention in my question... I'm trying to stay away from the Rails database for this project, so I'm not using "< ActiveRecord". All of my interactions are directly with the file system - no database persistence. Otherwise, that looks like it would be exactly what I'd need! – Josh Johnson Mar 12 '12 at 15:49
  • You should really mention you are not using anything activerecord related in your question and that you are trying to create a class that has to interact with the settings contained in files. My approach would be to create a class which accepts a file. It then reads in all the settings and stores them in a hash. This hash needs to intercept the setter ([]= I think) and store it off to the file as well as storing it in the hash. Then, as syntactic sugar you can add method_missing to the class so that when you do server_1.ip it'll check for an IP setting in the hash. – SpoBo Mar 13 '12 at 19:33
1

Made something for you.

Here is how it would work.

s = Settings.new(SettingsFileManager.new(some_file))

s.ip # returns whats in the file.
s.ip = 10.0.0.1 # overrides the new value.

I haven't written the way it interacts with the files yet so you'll have to write a proper SettingsFileManager.

If anything it should give you a good base to get started. But I wrote it primarily as a test to see what I know about ruby. Since it uses some semi-tricky stuff.

Hosted it on github too with some tests.

class Settings

  attr_accessor :settings

  def initialize(file_writer)
    @file_writer = file_writer
    read_settings_to_new_hash
  end

  def read_settings_to_new_hash
    @settings = fabricate_hash
    @settings.replace(@file_writer.read_keys)
  end

  def fabricate_hash
    InterceptedHash.new( &hash_saved_proc )
  end

  def hash_saved_proc
    Proc.new do |key, value|
      @file_writer.write_key(key, value)
    end
  end

  def method_missing(m, *args, &block)
    if @settings.has_key?(m) || args[0]
      if args[0]
        @settings[m.to_s.sub("=","").to_sym] = args[0]
      else
        @settings[m]
      end
    else
      raise "unknown setting"
    end
  end

end

# Not implemented. This should continue the logic to interact with whatever you want.
class SettingsFileManager
  def initialize(file)
    @file = file
  end

  # write the key and its value somewhere.
  def write_key(key, value)
    puts 'write_key', key, value
  end

  # should return hash of keys.
  def read_keys
    puts 'read_keys'
    Hash.new
  end
end

class InterceptedHash < Hash
  def initialize(&block)
    super
    @block = block
  end

  def store(key, value)
    super(key, value)
    @block.call(key, value)
  end

  def []=(key, value)
    store(key, value)
  end
end
SpoBo
  • 2,100
  • 2
  • 20
  • 28