How to successfully inherit ActiveRecord::Base? - ruby-on-rails

How to successfully inherit ActiveRecord::Base?
Environment: Ruby 2.0.0, Rails 4.0.3, Windows 8.1, PostreSQL 9.3.3, Devise 3.2.4
I have an operational app and would like to add a comprehensive logging class to it. This will be a complex class that not only logs messages but also creates an SQL database that logs transactions by object. I need this class available throughout all of the classes in the application.
To do this, I wanted to inherit ActiveRecord::Base into the class and then have all other classes inherit it, though I don't plan to use STI. That seemed to be a lot simpler in concept than in practice, even though I thought such inheritance was a common best practice. Am I missing something?
One of the initial tables was this:
class Device < ActiveRecord::Base
...
end
I set it up like this:
class XLog < ActiveRecord::Base
self.abstract_class = true
def initialize
end
end
class Device < XLog
...
end
Prior to this change, the app was working fine. After this change, when I login I receive:
ArgumentError at /devices/sign_in
wrong number of arguments (1 for 0)
The error occurs in:
bin/rails, line 4
bin/rails is:
#!/usr/bin/env ruby.exe
APP_PATH = File.expand_path('../../config/application', __FILE__)
require_relative '../config/boot'
require 'rails/commands'
Device is the Devise "User" class in this application and the error occurs when I try to login. If I change Device to inherit ActiveRecord::Base, it lets me login and run.
But, then I get another error whenever I call "new" on the other classes:
undefined method `[]' for nil:NilClass
I am definitely missing something when it comes to this inheritance. Advice appreciated.

The initialize method was throwing the error. It was triggering every time a subclass was initialized and was configured to accept 0 parameters. When I removed it, the whole thing started working. If I need it, I'll have to configure it to accept a variable number of parameters and pass them as expected, I guess.

Related

superclass mismatch error from class in Trailblazer operation when making changes to Rails code while server is running

I'm using the Trailblazer gem with Rails, and there's a Cell class inside one of my Trailblazer operations that starts throwing a superclass mismatch error whenever I change the code with the server running.
If I start the server and immediately start navigating the site, everything runs fine.
However, if change some code any time after starting the server, and then try to load a page on the site, I get a superclass mismatch error.
Turns out the name of my operation was not the same as the name of the file I created for the operation. I had recently changed the filename from register.rb to make_reservation.rb, but hadn't changed the operation class name from Register to MakeReservation. When I made the class name change as well, the superclass mismatch error stopped happening.
If you are toying with the Trailblazer book with Rails 5-pre you would need to watch out for the change in name spacing. Not having the name spacing properly resulted in a similar error.
Although in Rails 4, models inherit from ActiveRecord::Base in Rails 5 it is form ApplicationRecord.
Your app/concepts/thing/operation.rb in my case app/concepts/listing/operation.rb should be some thing like...
class Listing < ApplicationRecord
class Create < Trailblazer::Operation
def process(params)
#model = Listing.create(params[:listing])
end
end
end

Rails "superclass mismatch for class (TypeError)". A well documented error, but I need some tailored advice

Ok. I understand why I'm getting this error. According to another StackOverflow question, "That error shows up when you redeclare a class that’s already been declared". This question seems to point out the solutions, but not quite. I have some additional questions.
Here's what I have...
/models/item.rb
class Item < ActiveRecord::Base
..
end
class Theme < Item
end
class Setting < Item
end
This Item model has existed for quite some time. I recently added the sing inheritance for Theme and Setting.
As well as...
/models/setting.rb
class Setting < ActiveRecord::Base
..
end
/models/theme.rb
class Theme < ActiveRecord::Base
..
end
So it makes sense why I'm getting the error. I never got the error in my local workspace, only when I pushed everything to heroku, did my migrations, and then tried to run "heroku run rails c". As soon as I run that command, I get the error and immediately get booted out.
According to some answers, I should quit console and come back in. However, I can't get in to begin with. As soon as I launch "heroku run rails c", I get booted.
Additionally, if I completely wipe my DB, and remigrate everything, am I going to get the same error given the order of operations of these table creates, etc? I don't want to have to hack a solution to fix it everytime. If I run all my migrations, ideally everything would be working straight away.
What do I do to solve this issue?
You're trying to redefine the Theme and the Setting model. In your app/models/item.rb you define them as inherited from Item class and in the app/models/theme.rb and app/models/setting.rb you define them to inherit from ActiveRecord::Base directly.
You can see this error only in the heroku (probably production) environment because in dev env the eager loding option is turned off by default and therefore Rails does not load in all the classess when it boots.
Is your Item model using single table inheritance (STI)? Because that is the only case when you need to inherit the Theme and Settings model from your Item model.
If it is move your Theme and Setting class definitions to the app/models/theme.rb and app/models/setting.rb files accordingly and remove the definitions from there.
If not, then simply remove the Theme and Setting class definitions from the app/models/item.rb file and you'll be good to go.

rails resque and resque-send-later plugins causing "unitialized constant ClassName::Resque" error

i'm using the resque and resque-send-later PLUGINS (not gems) in my project.
I haven't put 'require' statements anywhere in the code at all (since they're plugins and so they must be included upon initialization).
the app is working perfectly locally, but on heroku, it shows an error
"const_missing: unitialized constant User::Resque"
my User model:
class User < ActiveRecord::Base
include Resque::Plugins::SendLater
def self.testingWorker1
# code to be run in the background
end
end
my User_controller: (where i'm calling the above method from)
class UserController < ApplicationController
def testingResqueWorker
User.send_later(:testingWorker1)
end
end
so I removed the line include Resque::Plugins::SendLater from the my model
it still works perfectly locally, but now on heroku it gives an error saying "method_missing: send_later"
my question is:
1. how do we 'include' or 'require' plugins in rails? are they automatically available to all controllers and models?
2. any ideas for how to fix the above errors?
Two thoughts
any reason why you aren't using the gems?
are you sure the plugins have been added to the git repository and therefore have been deployed to heroku?

Rails Delayed Job & Library Class

Hey we have a library class (lib/Mixpanel) that calls delayed job as follows:
class Mixpanel
attr_accessor :options
attr_accessor :event
def track!()
..
dj = send_later :access_api # also tried with self.send_later
..
end
def access_api
..
end
The problem is that when we run rake jobs:work: we get the following error:
undefined method `access_api' for #<YAML::Object:0x24681b8>
Any idea why?
Delayed_job always autoloads ActiveRecord classes, but it doesn't know about other types of classes (like lib) that it has marshaled in the db as YML. So, you need to explicitly trigger the class loader for them. Since DJ starts up the Rails environment, just mention any non-AR marshaled classes in an initializer:
(config/initializers/load_classes_for_dj.rb)
Mixpanel
A small gotcha, I followed Jonathan's suggestion, but I needed to add a require before the class name, so I'd use this for load_classes_for_dj.rb:
require 'mixpanel'
Mixpanel
Then it worked fine!

Rails RSpec with Multiple Databases

I run a Rails app, and we're in the process of splitting out our signup process to a separate app. The signup app has its own separate database (for CMS and collecting prospects), but it also needs to have access to the main database. This works really well using ActiveRecord::Base.establish_connection.
However, I'd like to be able to write some specs. The trouble is, how can I write specs/tests without clearing out my development database every time my tests run? If I go into the console in test mode, it's obvious the the test mode is hooked into the development database from my main app.
Here's what my database.yml file looks like:
development:
database: signup_dev
test:
database: signup_test
main_app_dev:
database: main_app_dev
main_app_test:
database: main_app_test
Based on this file, I'd like establish_connection to connect to connect to the database my_app_dev in development mode, and my_app_test in test mode. Any ideas?
We have a gem that is basically a collection of ActiveRecord models that connect to our legacy system. In our case we have all those models contained in a module from which all models related to the legacy database connects.
module Legacy
class Base < ActiveRecord::Base
establish_connection :legacy
end
class User < Base
end
end
With this setup it makes it really easy to switch out the database connection. If you really go for that automated detection you can put logic in your base class to determine which database to use:
module Legacy
class Base < ActiveRecord::Base
if Rails.env == 'test'
establish_connection :legacy_test
else
establish_connection :legacy
end
end
Or simply tell your module which connection to use in your spec helper:
# spec/spec_helper.rb
Legacy::Base.establish_connection(ActiveRecord::Base.configurations['legacy_test'])
Personally I would recommend the second option. Of course both solutions depend on namespaced models.
Peer
Ryan, we were also in the process of migrating from one datastore to another. We needed to develop against two databases and maintain separate migrations and fixtures for each.
I created a gem called Secondbase to help with this. Essentially, it allows you to manage two databases seamlessly in a single Rails app. Perhaps it will solve your issue as well: https://github.com/karledurante/secondbase
Here's what I came up with as a mixin:
# lib/establish_connection_to_master_database.rb
module EstablishConnectionToMasterDatabase
def establish_connection_to_master_database
case RAILS_ENV
when "development"
establish_connection :master_dev
when "test"
establish_connection :master_test
when "production"
establish_connection :master
end
end
end
ActiveRecord::Base.send(:extend, EstablishConnectionToMasterDatabase)
# models/subscription.rb
class Subscription < ActiveRecord::Base
establish_connection_to_master_database
end
# config/initializers/config.rb
require 'establish_connection_to_master_database'
In order for this to work with RSpec, this needs to be loaded in an initializer - apparently loading it in the environment file causes it to be loaded it too late, and it won't work.
We just used interpolation for this:
class ServiceModel < ActiveRecord::Base
establish_connection :"main_app_#{Rails.env}"
end
The funny :"main_app_" syntax makes a symbol from a string. This could be also written "main_app_#{Rails.env}".to_sym. In either case with Rails 4.1 this must be a symbol (under 3.2 we had just used a string).

Resources