3

I have two different classes that both represent objects that need to be persisted to my database and now I want to share the database client object between the two classes. I want to avoid instantiating the client object more than once.

Currently I do this by using a global variable

$client = Mysql2::Client.new(:database => "myDb", :user => "user", :password => "password", :host => "localhost") class Person def save $client.query("INSERT INTO persons") end end class Car def save $client.query("INSERT INTO cars") end end 

This works, but I am wondering if there are more correct ways to do this and why they are more correct?

2 Answers 2

4

You can inherit from a parent class. This allows you to share common functionality across objects and follows DRY (do not repeat yourself) programming principles. It will also allow you to protect your DB connection with locks, resuces, queues, pools, and whatever else you may want to do without having to worry about it in your children classes

class Record @table_name = nil @@client = Mysql2::Client.new(:database => "myDb", :user => "user", :password => "password", :host => "localhost") def save @@client.query("INSERT INTO #{@table_name}") if @table_name end end class Person < Record @table_name = "persons" end class Car < Record @table_name = "cars" end 

While we are on the subject, you should look at using ActiveRecord for handling your database models and connections. It already does pretty much anything you'll need and will be more compatible with other gems already out there. It can be used without rails.

Sign up to request clarification or add additional context in comments.

3 Comments

One of the reasons for my question was that I did not want to instantiate the database client object more than once. When using your solution does the fact that @@client is a class variable mean that every subclass shares the same object?
@SimonThordal A class variable is shared by all instances of a class source.
This answer has the right idea, but it could use some refactoring. @@client can be set outside of initialize (to avoid the if). The use of attr_accessor seems unnecessary since 1) it's only being called from inside the class and 2) table_name should always be the same for instances of the same class.
1

As an alternative on using inheritance, why not consider a simple Singleton pattern? This could make your models cleaner, by separating the responsibility outside your classes. And eliminating the need for inheritance.

The example below illustrates this. Only one, single instance of the DataManager class can exist. So, you'll only instantiate it once - but can use it everywhere:

require 'singleton' class DataManager include Singleton attr_accessor :last_run_query def initialize() if @client.nil? p "Initialize the Mysql client here - note that this'll only be called once..." end end def query(args) # do your magic here @last_run_query = args end end 

Next, calling it using the .instance accessor is a breeze - and will always point to one single instance, like so:

# Fetch, or create a new singleton instance first = DataManager.instance first.query('drop table mother') p first.last_run_query # Again, fetch or create a new instance # this'll actually just fetch the first instance from above second = DataManager.instance p second.last_run_query # last line prints: "drop table mother" 

For the record, the Singleton pattern can have some downsides and using it frequently results in a never-ending debate on whether you should use it or not. But in my opinion it's a decent alternative to your specific question.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.