share
Stack OverflowRuby class expects class variable but only in Rake task
[+2] [1] thumbtackthief
[2018-06-13 18:58:18]
[ ruby ]
[ https://stackoverflow.com/questions/50844404/ruby-class-expects-class-variable-but-only-in-rake-task ]

I am trying to seed my database with some dummy data, so I have this seed file:

db/seeds.rb

require 'require_all'
require_all 'lib'

Author.create(name: "Mark Twain")

My Ruby model and relevant methods:

lib/author.rb

class Author

    attr_accessor :name, :id

    def initialize(name, id=nil)
        @name = name
        @id = id
    end

    def self.make_object_from_row(row)
        # [1, "Mark Twain"]
        Author.new(row[1], row[0])
    end

    def self.create(name)
        author = Author.new(name)
        author.save
    end

    def save
        if self.id.nil?  # doesn't exist in the database yet
            sql = <<-SQL
                INSERT INTO authors (name)
                VALUES (?)
            SQL
            DB.execute(sql, self.name)
            sql = "SELECT last_insert_rowid()"
            self.id = DB.execute(sql)[0][0]
        else # just update the row in the db
            sql = <<-SQL
                UPDATE authors SET (name) = ? WHERE id = ?
            SQL
            DB.execute(sql, self.name, self.id)
        end
    end

Rakefile

require_relative './config/environment'

desc "Set up database"
task :db_setup do
    author_sql = <<-SQL
        CREATE TABLE IF NOT EXISTS authors(
            id integer PRIMARY KEY,
            name varchar(255)
        );
    SQL
    DB.execute(author_sql)
end

desc "Seed database"
task :db_seed do
    ruby "db/seeds.rb"
end

config/environment.rb

require 'bundler/setup'
Bundler.require

# setting up the database connection (old way)
DB = SQLite3::Database.new("db/development.db")

require_relative '../lib/author.rb'

When I run the rake task for db_seed I get the error . lib/author.rb:26:in save': uninitialized constant Author::DB (NameError)

The db_setup Rake task works fine. Also if I go into a pry from my console, I can instantiate a new Author without a problem (and it writes to the database). If I run the seed file from my command line, I get the same error.

I see that it's looking for an attribute DB on the Author class, but I don't see why, or why it's inconsistent in that I can create an Author from the command line but not from the Rake task--if the variable were undefined that shouldn't make a difference, correct?

(I'm also aware that using ActiveRecord would be much easier, but I'm not looking to use it right now)

If you find ActiveRecord too heavy, Sequel is worth checking out. It's not only an adaptable query builder but a model system if you want it. Any database requires migrations if you're going to use it in a production environment, and Sequel gives you that. - tadman
That should probably be UPDATE authors SET name = ? WHERE id = ? with no parens around name. - tadman
The update method works as it is. At the current time I don't wish to use any other gems or libraries--this is a learning exercise. I need to get the code working as it is, and also to understand what's causing the error. - thumbtackthief
If it's an academic exercise then that's an interesting project. I was just concerned this would be for production code, in which case you're creating a lot of technical debt here that you can never pay off. Does execute raise exceptions on errors or do you need to test the result of that method call manually? Each driver does this differently. I have a feeling you're getting push-back from your server that you're not properly capturing and dealing with. - tadman
This code won't be developed much past where it is right now, so no worries there. The rake task db_setup works fine. I also have a rake task which opens a Pry console, and when in there I can call the create and save methods (as well as my own find, all, and delete methods) without any problems. The only issue is the seed file (if I cut and paste the code in the seed file to the console, it works fine). My instinct is that I have a require wrong somewhere. - thumbtackthief
(1) The require_all method is the lazy way out and it might not be loading everything you expect, or loading it in the correct order. Have you tried, just for experimental purposes, of manually calling require_relative on each of the required files in the order they should be loaded? It's possible that whatever defines DB isn't loaded by the time that code is called. - tadman
I'm fuzzy on how to use require, but require_relative ./lib/author doesn't fix the error, whether I put it before or after requiring the config/environment file. Is there something else you think I should try? - thumbtackthief
Where does DB get defined? - tadman
in config/environment - thumbtackthief
(1) Are you sure you're loading that in? It's not in lib/ so maybe not in this code. - tadman
@tadman Yup, that was it. Thanks! Do you care enough about rep to turn it into an answer? - thumbtackthief
[+2] [2018-06-14 20:54:18] tadman [ACCEPTED]

When you see errors like "uninitialized constant" popping up and you're sure you've defined that constant in a file somewhere, make sure you're loading that code in before the method with the error runs.

It looks like in this case config/environment wasn't loaded before DB was referenced, so it can't complete.

Due to how Ruby searches for constants it's presented as Author::DB because the code was running inside of the Author namespace and that's where searches start.


1