Step-wise refactoring and has-one

Hi There,

Wondering if anyone has thoughts on this. Right now my User has lots of
responsibilities. I want to start to move some of them from a User to a
Profile (where a user has-one Profile). I don’t want to do any big
refactorings, so I want to take small steps so I can commit working code
that I could push to master if necessary every hour or so.

I was trying to get User to delegate :bio, :website, :to =>
:@current_profile
(real situation has a lot more complexity, but that’s the first step).

Trying to figure out best approach to this because of course when
factories (Factory_girl) or my code call a user, they want to call
user.bio and user.bio=, so before they call I have to ensure that I have
an @current_profile.

How does Ruby actually call instance variables? Does it make sense for
me to def a method to overload the getter for the current_profile
instance variable that looks to see if the actual instance variable
exists and if not finds/creates it?

Just trying to find the best way to approach the problem. Any input much
appreciated.

Best Wishes,
Peter

On 9 Aug 2011, at 22:08, Peter B. wrote:

Wondering if anyone has thoughts on this. Right now my User has lots of
responsibilities. I want to start to move some of them from a User to a Profile
(where a user has-one Profile). I don’t want to do any big refactorings, so I want
to take small steps so I can commit working code that I could push to master if
necessary every hour or so.

I was trying to get User to delegate :bio, :website, :to => :@current_profile
(real situation has a lot more complexity, but that’s the first step).

Trying to figure out best approach to this because of course when factories
(Factory_girl) or my code call a user, they want to call user.bio and user.bio=,
so before they call I have to ensure that I have an @current_profile.

As an aside: if your User has_one Profile, then normally you’d just
access that via User’s instance method ‘profile’, which ActiveRecord
provides. Is there a particular reason you need to use a separate
instance variable to reference the profile?

How does Ruby actually call instance variables? Does it make sense for me to def
a method to overload the getter for the current_profile instance variable that
looks to see if the actual instance variable exists and if not finds/creates it?

AFAIK, there isn’t any way to hook into the access of an instance
variable. Overriding a getter method will only work if you only ever
access that instance variable via the getter method and not directly;
unfortunately for your case, ActiveSupport’s Delegation module will
generate code that accesses your @current_profile instance variable
directly.

As a first attempt, I’d probably just use ActiveRecord’s
after_initialize hook in User to make sure I find/create a profile
whenever a new User instance is made.

Not sure if that approach will play well with your factories, but then
they probably ought to be creating the Profile instance explicitly
anyway.

Chris

On Aug 9, 2011, at 5:43 PM, Chris M. wrote:

On 9 Aug 2011, at 22:08, Peter B. wrote:
As an aside: if your User has_one Profile, then normally you’d just access that
via User’s instance method ‘profile’, which ActiveRecord provides. Is there a
particular reason you need to use a separate instance variable to reference the
profile?

Yeah - MongoMapper. I keep on running into issues with the has_one
relationship, so I’m persisting a current_profile_id as an ObjectId and
I need to handle the retrieval of the profile usine a
Profile.find(current_profile_id)

How does Ruby actually call instance variables? Does it make sense for me to
def a method to overload the getter for the current_profile instance variable that
looks to see if the actual instance variable exists and if not finds/creates it?

AFAIK, there isn’t any way to hook into the access of an instance variable.
Overriding a getter method will only work if you only ever access that instance
variable via the getter method and not directly; unfortunately for your case,
ActiveSupport’s Delegation module will generate code that accesses your
@current_profile instance variable directly.

Hmmm, OK, thanks

As a first attempt, I’d probably just use ActiveRecord’s after_initialize hook
in User to make sure I find/create a profile whenever a new User instance is made.

I can’t find support for after_initialize in MM unfortunately
(Callbacks // MongoMapper), but I can
look for the closest possible on the MM list.

Not sure if that approach will play well with your factories, but then they
probably ought to be creating the Profile instance explicitly anyway.

That’s certainly something I can do. So probably use a callback for the
runtime code and just pass in the object in the factories. Seems like a
way I can go - thanks!

Best WIshes,
Peter