Removing an association on an AR model via monkey patching

How can I remove an association from an AR model with a monkey patch?

Assume:

class Foo < AR::Base   has_many :bars end

It's a long story, but in one particular data loading (not running the app. context), I'd like to remove the has_many association to :bars.

Can I do that?

Thanks, Wes

It sounds like you want to make sure that code that does this:

@foo.bars

would raise a NoMethodFound exception? If so, you can just reopen the class:

class Foo   def bars     raise NoMethodError.new("undefined method 'bars'")   end end

Then,

@foo.bars # => raises exception

However, this isn't really removing all of remnants of the association, so again it depends on what constitutes "removed enough" for your situation.

Jeff purpleworkshops.com

Unless you reference the association, it won't be accessed. Am I (Are we) missing something here? Just don't use the association.

-Rob

Rob Biedenharn http://agileconsultingllc.com Rob@AgileConsultingLLC.com

When I call Invoice.find_all_by_im_invoice_state("Paid").each the Invoice class is loaded.

When the Invoice class is loaded, all of its class level association directives are executed. When it hits the one that doesn't have a backing table, it fails.

So it's at the point where the class (not the data) is loaded that the
problem occurs ? You might be in a tight spot then because it's going
to be hard to remove the association before the class exists. I can
think of two ways, neither of which is very nice.

define a new class Invoice < ActiveRecord::Base inside your fixture
generation code. if you don't need any of Invoice's methods then
you're fine with just this

Override ActiveRecord::Base.has_many to check if self is invoice and
the association name is the bad one. if it is, do nothing. if not let
the normal code run.

Fred

Frederick Cheung wrote:

When the Invoice class is loaded, all of its class level association directives are executed. When it hits the one that doesn't have a backing table, it fails.

So it's at the point where the class (not the data) is loaded that the problem occurs ? You might be in a tight spot then because it's going to be hard to remove the association before the class exists.

Actually, the class needs to exist and I just need to temporarily remove the association.

Can you show us the has_many part of your Invoice class?

Product is a model in one of my client projects. I can do: $ script/console Loading development environment.

Product

=> Product

class Product; has_many :foobars; end

=> [:build_to_foobars]

p=Product.find(:first)

=> #<Product:0x3edb0e0 @attributes={...}>

p.methods.include?('foobars')

=> true

p.foobars

NameError: uninitialized constant Product::Foobar

Notice that there is no error when the:    has_many :foobars gets processed. When I find a product, it has a foobars method, but it doesn't work.

Perhaps you are defining your association is a way that causes pre-mature loading of the associated model?

define a new class Invoice < ActiveRecord::Base inside your fixture generation code. if you don't need any of Invoice's methods then you're fine with just this

I need to be able to do a find on Invoice, which is why I have the problem in the first place, so this probably won't work.

Override ActiveRecord::Base.has_many to check if self is invoice and the association name is the bad one. if it is, do nothing. if not let the normal code run.

This may work and I will give it a shot. Thanks for the idea.

Wes

'Cause this seems like a lot of work that might not even be necessary.

-Rob

Rob Biedenharn http://agileconsultingllc.com Rob@AgileConsultingLLC.com

The has_many part of the Invoice class is actually provided by a plugin. And inside of that plugin, a set_table_name was being done to point to the offensive table.

I got this to work by making the inclusion of that plugin dependent on the setting of RAILS_ENV. Which isn't pretty, but works.

Not sure that I will leave the change in, but I did (finally) get my data loaded. Thankfully, I have Erb to make the fixtures as flexible as I need them to be.

Thanks for all of the help, everyone.

Wes