R G
R G

Reputation: 47

Ruby: Mildly 'exotic' inheritance doesn't work?

I would like to factor a bunch of common code from subclasses into a superclass method. The superclass method must refer to a nonexistent (in the superclass) method that will be defined in the subclasses. But I can't get this to work.

This is one try out of many multiple variations I have tried:

class Superclass
    def chunk_of_code
        # <code...>
        nonexistant_superclass_method_defined_in_subclass params
        # <more code...>
    end
end

class Subclass < Superclass
    def nonexistant_superclass_method_defined_in_subclass params
        # whatever...
    end
end

Subclass.new.chunk_of_code params

This doesn't work. Other variations don't work either. Is this kind of coding possible in Ruby (I thought it was)? I did this kind of thing all the time working in Smalltalk.

Any way to achieve what I want? Please avoid advising me to use "mix-ins" or "modules," as I'd just like to just learn and use Ruby's inheritance for right now.

*Running latest version of Ruby.

Thanks.

EDIT: This is in a Rails app. The superclass is ApplicationController.

EDIT: Here is actual code from one of many iterations I've tried to do this. This particular example craps out with "undefined method `each' for nil:NilClass" in the view, apparently because the whole thing is running in the context of the super (where it isn't defined) instead of the sub, or at least that's my interpretation:

class ApplicationController < ActionController::Base
    protect_from_forgery
    before_filter :authenticate_registration!

    # models and x defined in subclass
    def index
        models = x.where registration_id: current_registration.id

        respond_to do |format|
            format.html # index.html.erb
            format.json { render json: models }
        end
    end
    # more code here...
    # ...
end

class PositionsController < ApplicationController
    def x
        Position
    end

    def models= blah
        @positions = blah
    end

    # more code here...
    # ...
end

Upvotes: 0

Views: 138

Answers (4)

railsdog
railsdog

Reputation: 1501

Over on the model side of Rails, I routinely use:

class GenericModel < ActiveRecord::Base
  self.abstract_class = true

  # define all the generic behavior methods/ model stubs you want.
  # model-specific classes can override to their hearts content
  # or use the inherited implementation

end

class Feature < GenericModel
  # model specific methods, and/or overrides
end

and I use a

class GenericController
  # basic show implementation for example
  def show
    @object = params[:controller].singularize.camelcase.constantize.find(params[:id])
    respond_to do |format|
      format.pdf { render :layout => false }
      format.html  # show
      format.xml { render :xml => @object.to_xml }
    end
  end
end

If a specific model's show behavior isn't any different than generic, then that method doesn't appear in that 'model'_controller.rb.

Upvotes: 0

Frederick Cheung
Frederick Cheung

Reputation: 84182

Your error is actually nothing to do with inheritance and is on this line

models = x.where registration_id: current_registration.id

This is potentially ambiguous: does this mean call the method models= or does it mean assign to a local variable called models? In this (and similar) situation ruby assumes you're trying to deal with the local variable. If you want to call the method instead you need to do

self.models = x.where registration_id: current_registration.id

Since you models= method doesn't get called, @positions is nil and I assume your view tries to use it.

You might also be interested in gems such as make_resourceful that handle this common controller stuff.

Upvotes: 1

TEOUltimus
TEOUltimus

Reputation: 184

A way to do this is to define it in the parent and raise NotImplementedError as the behavior of the method. By the way what you are trying to do is create an abstract class, which is facilitated more in certain other languages like Java.

Upvotes: -1

jdoe
jdoe

Reputation: 15779

The only error you have here is the definition of the chunk_of_code. This method has to accept some formal parameter, like:

def chunk_of_code params

And then you're free to call it:

params = 'something'
Subclass.new.chunk_of_code params

Upvotes: 3

Related Questions