I have a parent class that looks like this:
class Record
attr_accessor :id, :url, :votes, :title, :first_name, :last_name, :selfdb
def initialize(args = {})
args.each { |name, value| instance_variable_set("@#{name}", value) }
@selfdb = "#{self.class.name.downcase}s"
end
def self.find(id)
DB.results_as_hash = true
hasharray = DB.execute("SELECT * FROM ? WHERE id = ?", @selfdb, id)
hasharray.empty? ? nil : new(hasharray[0].transform_keys(&:to_sym))
end
end
Each child class of Record has a matching database table whose name is "#{name of the class}s", so the class "Post" is connected to a table named "posts".
My goal is to have self.find(id) to work on any children of this class. The solution I tried was to save the class' name into a string variable with an "s" at the end (so that class Post -> "posts", for example), to match the name of the database, as I tried in the instance variable @selfdb, but this does not work.
Calling @selfdb on the children classes confirms that it does correctly create the string for different classes, but running the sqlite with it inserted as the table name just returns nil.
This might be a very roundabout way of doing it, any suggestions are welcome. I am still learning and this is just a bootcamp assignment.
Edit: i realized one mistake I made: since self.find(id) is a class method, it can't use an instance variable. However, when I change the class method to work like this:
def self.find(id)
selfdb = "#{self.name.downcase}s"
DB.results_as_hash = true
hasharray = DB.execute("SELECT * FROM ? WHERE id = ?", selfdb, id)
hasharray.empty? ? nil : new(hasharray[0].transform_keys(&:to_sym))
end
... it still does not properly insert into the sqlite string.
CodePudding user response:
You define @selfdb
in the initialize method which means it is only available in on the instance level. But your self.find
method is a class method and therefore @selfdb
is undefined on the class level.
I would suggest adding a class method that returns the table name like this
def self.table_name
"#{name.downcase}s"
end
which you can then be used in the find
class method like this
def self.find(id)
# ...
hasharray = DB.execute("SELECT * FROM ? WHERE id = ?", table_name, id)
# ...
end
and in instance methods (for example to save a record) you need to use self.class.table_name
or you could add a delegator to forward a table_name
instance method call to the class method:
extend Forwardable
def_delegators :"self.class", :table_name