1

I have my Rails 5 ApplicationRecord:

class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
end

and a bunch of models that inherit from ApplicationRecord. Now, I would like each model name to map to its database table in a customized way. For example, I can do:

class MyModel < ApplicationRecord
  self.table_name = 'MY_MODELS'   # overrides default 'my_models'
end

But since all the mappings are predictable, I thought I would just do that in the base class:

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

  def self.table_name
    self.name.underscore.pluralize.upcase
  end
end

...but that didn't work, even though technically class methods should be inherited by the subclass. (Any idea why?)

I also tried adding a method that did something like this:

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

  def self.inherited(subclass)
    subclass.table_name = subclass.name.underscore.pluralize.upcase
  end
end

This didn't work either. Any idea how I can do this?

TylerH
  • 20,799
  • 66
  • 75
  • 101
Jake
  • 15,007
  • 22
  • 70
  • 86
  • I guess this should have worked or maybe you need to reload! your server or console in order for it to take effect. `class ApplicationRecord < ActiveRecord::Base self.abstract_class = true def self.table_name self.name.underscore.pluralize.upcase end end` – oreoluwa Mar 25 '16 at 18:45

2 Answers2

2

I ended up solving this by adding a Concern that implements the table_name function for each model.

Jake
  • 15,007
  • 22
  • 70
  • 86
1

The main reason why your approach failed was due to this line self.abstract_class = true. What does this line do?

It makes the class an abstract class. In rails, an abstract model/class is meant to be inherited by other models in your application. They have no tables in your application's database and they cannot be instantiated i.e they cannot have objects. Also, all models inheriting from ApplicationRecord will be omitted from its hierarchy.

The simple solution to this, i.e. to have your models included in your ApplicationRecord hierarchy is to add validations to your model. So in your case, this will be:

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

  def self.table_name
    self.name.underscore.pluralize.upcase
  end
end

class MyModel < ApplicationRecord
  validates :type, presence: true
end

Adding the validation will put MyModel in ApplicationRecord hierarchy and Active Record will continue to derive the correct table name. Offcourse, for multiple models, you will have to create a concern and then include it in all of your desired models.

You can read more about this behavior here

theterminalguy
  • 1,842
  • 18
  • 20