multiple_table_inheritance icon indicating copy to clipboard operation
multiple_table_inheritance copied to clipboard

How to reference a child attribute from an inherited method in the parent?

Open creativetags opened this issue 10 years ago • 8 comments

Is it possible to do something like:

class Employee < ActiveRecord::Base
  acts_as_superclass
  belongs_to :team

  def give_date
    self.training_completed_at
  end
end

class Programmer < ActiveRecord::Base
  inherits_from :employee, :methods => true
end

@programmer = Programmer.first
@programmer.give_date

This is a silly example but is something like this possible?

creativetags avatar Nov 12 '14 16:11 creativetags

Yeah, that's the intention of the :methods option on the inherits_from call. I will say though that I created this gem for Rails 3.x, and the internals have changed quite a bit since then that I can't promise this gem will still work under 4.x. (In fact, I'm pretty certain that it won't.)

mhuggins avatar Nov 12 '14 16:11 mhuggins

With that said, I'm definitely open to updates on the gem to make it work, but it's not something I have time for or actually need right now to be able to focus any kind of time on it. If you wish to pursue, I'm happy to accept pull requests to get it fixed up! :)

mhuggins avatar Nov 12 '14 16:11 mhuggins

I'm running rails 3.2.20 so it's ok at the moment but I would like to upgrade my app to rails 4 at some point.

Actually what I'm trying to do is: @employee = Employee.first # assume first employee is a Programmer @employee.give_date

I'm getting undefined method training_completed_at for #<Employee

creativetags avatar Nov 12 '14 16:11 creativetags

Where is training_completed_at defined?

mhuggins avatar Nov 12 '14 16:11 mhuggins

I'm using your example so:

create_table :programmers, :inherits => :employee do |t|
  t.datetime :training_completed_at
end

creativetags avatar Nov 12 '14 16:11 creativetags

Okay, I can explain what is going on. The give_date method is properly being delegated to the Employee object, but then the Employee object tries to call training_completed_at on itself. This doesn't work because you defined it on Programmer, not Employee. The delegation is intended for methods that exist on the parent record. Since training_completed_at exists on the programmer itself and not other inheriting classes, why not just call that method directly?

mhuggins avatar Nov 12 '14 16:11 mhuggins

So I have 7 child classes and 5 of them have :name attributes. I've a method first_name that returns the first word from the name attribute. I want to go through each of the parent's objects (filtered to just the 5 that have names) and print their first_name.

creativetags avatar Nov 12 '14 16:11 creativetags

This sounds like something that can't (currently) be done in the approach you're taking, in that there's no existing method to access the child from the parent. Either this method could be added (shouldn't be too hard), or else you'll need to try a slightly different approach. Adding this method would probably look as easy as something like:

module MultipleTableInheritance::Parent::Base::InstanceMethods
  def child
    send(subtype_column.to_sym).constantize.find_by_id(id)
  end
end

You could then call child.whatever from the superclass.

If you're trying to access first_name, and that only exists on 5 of the 7 models, I'd consider defining them on the remaining 2 models, e.g.:

class Employee < ActiveRecord::Base
  acts_as_superclass
end

class Programmer < ActiveRecord::Base
  inherits_from :employee

  validates :name, presence: true

  def first_name
    name.strip.split(/\s+/).first
  end
end

class Manager < ActiveRecord::Base
  inherits_from :employee

  validates :first_name, presence: true
end

mhuggins avatar Nov 12 '14 17:11 mhuggins