Rails STI override model_name in parent class for all subclasses
Asked Answered
F

2

5

I am using STI in a Rails app and in order to not have to define routes for all subclasses, I put the following in each subclass:

def self.model_name
  Mapping.model_name
end

In the above example, Mapping is the parent model name. Example:

class UserMapping < Mapping; end

Having to put this in each subclass is not very DRY, so I'm looking for a way to set that in the parent somehow, so that each class that inherits from the parent automatically has the model name set as the parent model name.

Perhaps there is even a better way to overcome the routing issue that arises from STI unrelated to setting the model_name - I'm open to suggestions!

Thanks in advance!

Firer answered 8/4, 2015 at 23:34 Comment(0)
H
9

Put this in your Mapping class:

class Mapping < ActiveRecord::Base
  def self.inherited(subclass)
    super
    def subclass.model_name
      superclass.model_name
    end
  end
end

Afterwards, all child classes of Mapping will also inherit the parent's model_name.

Headon answered 18/12, 2015 at 0:20 Comment(0)
B
3

Another option is to override the model_name method in the superclass to return a custom ActiveModel::Name:

class Mapping < ActiveRecord::Base
  def self.model_name
    ActiveModel::Name.new(base_class)
  end
end

By default model_name passes the current class as the first argument to ActiveModel::Name.new, so each sub-class will receive a different name based on their class. ActiveRecord models have a base_class method which we can use instead to get the base of a single-table inheritance hierarchy.

If you cared to, you could also name it something completely different. This might be useful when you're trying to transition a model to a new name:

class Mapping < ActiveRecord::Base
  def self.model_name
    ActiveModel::Name.new(self, nil, "AnotherMapping")
  end
end

More in the docs

Banville answered 28/10, 2019 at 0:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.