Cannot connect to two postgres databases in rails 3.2. - ruby-on-rails-3

I've tried a few methods found on stack overflow for connecting to two database in rails two however non of them are working. Here's what I've got at the moment:
In the database.yml there's two connection settings:
development:
adapter: postgresql
host: localhost
database: blerg
username: postgres
encoding: utf8
production:
blah...
test: &test
blah...
cucumber:
<<: *test
static_api_development:
adapter: postgresql
host: localhost
database: blerg-static-api
username: postgres
encoding: utf8
static_api_production:
blah...
static_api_test:
blah...
And then I have lots of normal models in the rails app, but also the odd special model that need to connect to the other database, here's how I've set it up...
There is a module in the models folder called static_table.rb which has this content:
class StaticTable < ActiveRecord::Base
self.abstract_class = true
establish_connection "static_api_#{Rails.env}"
end
Then the special models that need the other tables have this:
class ContentItem < StaticTable
self.table_name = 'content_items'
end
However if you call ContentItem.all in a controller it says the 'content_items' table does not exist and the database connection is showing as 'blerg' not the 'blerg-static-api' which it should be.
Any help would be much appreciated thanks.

Try to establish_connection in ContentItem too.

The issue is that inheritance doesn't work that way.
Consider the source of #establish_connection:
def establish_connection(owner, spec)
#class_to_pool.clear
raise RuntimeError, "Anonymous class is not allowed." unless owner.name
owner_to_pool[owner.name] = ConnectionAdapters::ConnectionPool.new(spec)
end
(Let's suppose owner_to_pool is actually #owner_to_pool for simplicity.)
Inside the StaticTable class, you invoked establish_connection within the class context. This updates #class_to_pool and #owner_to_pool, which are instance variables of StaticTable. (Some refer to these as class instance variables.) The accepted answer in this question goes into a detailed explanation.
The main problem is that even though ContentItem extends StaticTable, it does not inherit #class_to_pool and #owner_to_pool, and thus does not know that it should be establishing a connection to static_api_*.
There are two ways to fix this. First, you can use establish_connection in every model that should be using a static_api_* connection. This is simple, but not DRY. A better way is to create a Rails concern and include it in the necessary models.
module StaticConnectionConcern
extend ActiveSupport::Concern
included do
establish_connection "static_api_#{Rails.env}"
end
end
Then in your models,
class ContentItem < ActiveRecord::Base
include StaticConnectionConcern
end
Using Rails concerns, when StaticConnectionConcern is included in ContentItem, whatever is inside the included block is invoked in ContentItem's class context. You can create a app/concerns directory for concerns, and then tell Rails to autoload them by editing config/application.rb:
config.autoload_paths += %W(#{Rails.root}/app/concerns)
I strongly recommend the second way. As your application grows and becomes more complex, the StaticConnectionConcern might grow to include other methods as well.

Related

Create module that throws exception in rails if conditions not met on load

I have a module in a rails 3 app that's included in multiple models. I want to force the app to fail to load if any of the models do not have an appropriate attr_accessor defined. Due to the architecture of the app it's not feasible to include the attr_accessors as a part of the module to be added to the class during the self.included function.
Here's what I've tried at present:
module MyModule
def included(base)
raise "Accessor 'enabled' is not defined in #{base.name}" unless base.method_defined? :enabled
end
end
class MyModel < ActiveModel::Base
# attr_accessor :enabled
attr_accessor :attr_1, :attr_2
include MyModule
end
In this instance, I'd want the app to fail to load because MyModel does not have an enabled method.
Your code should work - on production. In development the classes in app/models are only loaded if used unless you set
config.cache_classes = true
in config/environments/development.rb. But that makes developing really no fun, since you have to restart your webserver every change to test your changes. On rails 4 you have another configuration option
config.eager_load = true
So you do not need to cache classes to get the behaviour to have loaded every class on starting your server / console.
If it's really only attribute accessor you check, it's better just to set it on including the module. And if you work with modules in rails: have a look into http://www.rubydoc.info/docs/rails/3.2.8/ActiveSupport/Concern
There you can just call attr_accessor :enabled in the included block.

How Do I Add Methods To ActiveRecord::Base?

I'm trying to create a customized ActiveRecord::Base that includes additional metadata about the connection. I see two ways to go about this:
1.) Inherit from ActiveRecord::Base and add methods & fields in this subclass.
2.) Encapsulate an ActiveRecord::Base object inside my own class
1 has all kinds of problems with the inability to override initialize, weird problems where it doesn't seem to have custom methods I've added, etc.
undefined method `set_profile' for #<Class:0xf041f0>
2 I have not been able to figure out, due to problems with using ActiveRecord::Base.new
I am trying to make an all-purpose ActiveRecord class that I can dynamically establish_connection & set_table_name on, (i.e. not have one underlying table that this ActiveRecord::Base represents) but I can't seem to find a way to accomplish it. Any ideas?
This works:
class MyTable < ActiveRecord::Base
establish_connection $config['custom-db-config'];
set_table_name 'MY_TABLE'
end
but I need a class I can call these things on repeatedly.
Not entirely sure why you'll want that, but maybe you can try this?
module ActiveRecord
class Base
def self.your_method
# implementation goes here
end
end
end
You will need to save this file and put it in config/intializers.
You can also extend the ActiveRecord::Base class in order to add the those methods dynamically which are directly callable by the class inheriting the ActiveRecord::Base...Many acts_as plugins are defined and made according to this practice...

Rails 3 - table name being pulled from PARENT model?! (ApplicationModel)

I just inherited a project. That project has upgraded to Rails3, and is lacking an application_model. I'm trying to implement it. I've extended all other models from it. The problem is that for some reason, when trying to determine the table name, ActiveRecord is using ApplicationModel, rather than the child model so I'm getting:
Table "your_db.application_models" doesn't exist.
Any thoughts? Why would it be pulling from the app model? Any idea on how to fix?
Thanks!
Apparently, here's the issue (according to what I found on this page: rails - root model or application model):
ActiveRecord normally detects when you subclass an already subclassed ActiveRecord::Base and uses this to turn STI (single table inheritance) on.
ApplicationModel will be an actual model that is expected to have a table in your database. This can lead to problems down the line.
To fix these two problems, you have to set abstract_class to true for ActiveRecord to properly function.
class ApplicationModel < ActiveRecord::Base
self.abstract_class = true
end
In contrast to an abstract ActionController, abstract_class must set to true which means the developer must know they cannot remove this line from ApplicationModel. With ApplicationController you can do pretty much whatever you want to it.

avoiding code duplication in Rails 3 models

I'm working on a Rails 3.1 application where there are a number of different enum-like models that are stored in the database. There is a lot of identical code in these models, as well as in the associated controllers and views. I've solved the code duplication for the controllers and views via a shared parent controller class and the new view/layout inheritance that's part of Rails 3.
Now I'm trying to solve the code duplication in the models, and I'm stuck. An example of one of my enum models is as follows:
class Format < ActiveRecord::Base
has_and_belongs_to_many :videos
attr_accessible :name
validates :name, presence: true, length: { maximum: 20 }
before_destroy :verify_no_linked_videos
def verify_no_linked_videos
unless self.videos.empty?
self.errors[:base] << "Couldn't delete format with associated videos."
raise ActiveRecord::RecordInvalid.new self
end
end
end
I have four or five other classes with nearly identical code (the association declaration being the only difference). I've tried creating a module with the shared code that they all include (which seems like the Ruby Way), but much of the duplicate code relies on ActiveRecord, so the methods I'm trying to use in the module (validate, attr_accessible, etc.) aren't available. I know about ActiveModel, but that doesn't get me all the way there.
I've also tried creating a common, non-persistent parent class that subclasses ActiveRecord::Base, but all of the code I've seen to accomplish this assumes that you won't have subclasses of your non-persistent class that do persist.
Any suggestions for how best to avoid duplicating these identical lines of code across many different enum models?
I found a solution to the code sharing for Rails 3 models, so thought I'd share it with others. It turns out ActiveModel does have everything I need (so far, at least). I created an Enum module using ActiveSupport::Concern, ActiveModel::Validations, and ActiveModel::MassAssignmentSecurity, and I include the module in each of my enum models:
module Enum
extend ActiveSupport::Concern
include ActiveModel::Validations
include ActiveModel::MassAssignmentSecurity
included do
attr_accessible :name
validates :name, presence: true, length: { maximum: 20 }
before_destroy :verify_no_linked_videos
private
def verify_no_linked_videos
unless self.videos.empty?
self.errors[:base] << "Couldn't delete object with associated videos."
raise ActiveRecord::RecordInvalid.new self
end
end
end
end
The way the Rails 3 team pulled out the non-database code from ActiveRecord into ActiveModel really is pretty slick! The following links helped solidify my understanding of how to use this stuff:
http://www.fakingfantastic.com/2010/09/20/concerning-yourself-with-active-support-concern/
http://asciicasts.com/episodes/237-dynamic-attr-accessible

How do you solve FixtureClassNotFound: No class attached to find

When running my tests I get this error:
FixtureClassNotFound: No class attached to find
What causes this error and how to fix it?
Most likely this happens because a custom table name is used for a Model (using the set_table_name) or the model is in a module.
To solve, you need to add a set_fixture_class line in the test_helper.rb before the fixtures :all line:
class ActiveSupport::TestCase
self.use_transactional_fixtures = true
.
.
.
set_fixture_class my_table_name: MyModule::MyClass
fixtures :all
end
In this case the fixtures file should be called my_table_name.yml
NOTE: It would be helpful if you included the stack trace and the full error message.
In your test/test_helper.rb class, there is a line like
fixtures :all
This tells the framework to look in the directory test/fixtures and try to load each of the YAML files that it sees there and then save them to the DB. So my hunch is that you have a file in there that does not have class in app/models with the singularized name. In other words, if there is a file test/fixtures/posts.yml, then when you run your tests, the framework will look for a class named Post to load your data in.
So the first thing I would do is check to see if you have a fixture file that is not associated with one of your model classes (maybe you deleted a model but forgot to delete the fixture?)
If that doesn't work, try changing the line in your test helper to explicitly load the fixtures you need. So if you only want to load fixtures for an object named Post and an object named User, you will change:
fixtures :all
to
fixtures :posts, :users
in test_helper.rb and you should see the error go away (although other errors may now appear because your fixtures are not loaded.0
In the Event that the Class is an irregular class in terms of naming such as fish, sms
it could have been created by using the --force-plural flag
i.e
rails g model sms --force-plural
in that case you would set up an inflection which is set up under
config/initializers/inflections.rb
an example of such is this
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.plural /^(ox)$/i, '\1en'
inflect.singular /^(ox)en/i, '\1'
inflect.irregular 'person', 'people'
inflect.uncountable %w( fish sheep )
end
In this way the class can be recognized as you declared it
I got this error when I made a mistake generating some scaffold code. I used a plural model name, and that just confused the fixture loading, I guess. Regenerating the scaffold with a singular model name fixed the problem.