Jonathan Bennett

Using Super with Dynamic Methods


I was working with the rails-money gem and I was trying to do some stuff with inheritance.

I was going to do multi-parameter arguments coming in from the form and with that I wanted to do price, I wanted to override the setter for the price.

So this was something like this.

So I had my class, I was pulling from ActiveRecordBase, or ApplicationRecord.

This is inside of the test class for monetize.

So in here I’m actually specifically reusing the products table but I don’t want to inherit from Products specifically.

This is because I’m testing inheritance so I don’t want to do that.

So what I’ve done here is I’ve just overwritten the price= function and in here I’m just going to cause some side effect.

So looking at this what I want to do is I want to be able to say my I have a new product with price 10 and I expect that the price is going to be $10 and that there’s going to be the side effect that that’s going to be true.

So that’s what I’m expecting from this.

So I run this, it blows up and says that there’s no super class method for price=.

So the reason that it’s happening if I run it again and show this with the ancestry on it, we can see that our MyProduct class is inheriting from some generative stuff for the associations.

That’s coming from ActiveRecord::Base and then it’s including monetizable and then a whole bunch of other stuff.

So the thing is that monetizable, when it runs it’s generating that price= method on the actual MyProduct class.

So there’s no inheritance in that.

So if we look over here what’s happening here is that we’re defining this method on the MyProduct class.

So what we want to do is actually kind of fork this and well there’s two ways to solve this problem.

One is that we can go in here and we can do something where we grab the the old price as a reference and then in here we can go self.oldPrice = value.

What we’re doing here is we’re basically making the new method.

We’re grabbing that reference to that old method and then we’re calling that old method in our new method.

So if we do that and we run the tests this should pass.

Why are you wrong there?

Did I do the order wrong?

I do not do aliases very often.

I think that’s what it is wrong.

Let’s see.


So that passes.

I don’t want to do the ceremony every time.

This is annoying.

I just want to super it.

So let’s put that back and go back to super.

So this is gonna be failing again.

What we want to do is we want to change monetizable to actually create that class, that class inheritance structure.

So what I’m gonna do is I’m gonna come in here and I’m gonna just I’m gonna name this so I’m gonna say something like module name is DynamicMoneyAttributes. That doesn’t really matter we just don’t want to step on toes so it’s gonna be something a little bit specific. If we jump down now to where we define those methods so we can see here we’ve got we were here defining so it’s be the price, price=, price_cents= etc.

So we have all of those that we are defining so we actually want to wrap all of these inside of the inheritance structure.

So to do that we can do this.

So what we want to do is we actually want to create a dynamic module so if it’s already been defined that module name then we are going to grab it and if it has not been defined we’re gonna create it and here we’re gonna include it.

So now this puts this module into the inheritance structure and actually if we run this again so it’s gonna fail which is good that’s we haven’t fixed it yet but now we can see here we have the MyProduct::DynamicMoneyAttributes module so that there is is injected into the into the whole thing.

The reason that we do this lookup first is if we call this several times we’re gonna want to have a single module that has all of the methods that we’ve that we’ve added to it.

So now what we can do is in here instead of putting all these onto the class we can grab the whole bunch of them and we can define those onto the module itself.

So if we do that and we run the tests this now all passes and that’s because this so the MyProduct is now looking when we say super it’s looking here at the DynamicMoneyAattributes and that’s where we have defined those methods that are able to access those fields.

So this lets us do the lookup without you use the whole song and dance of doing the aliasing to the old method.

All right that’s a quick one but how you can add things to the inheritance chain if you are doing dynamic method creation.