Ruby on Rails: Using table_name_prefix and namespace to organize models

icelandcheng
3 min readMay 30, 2021

When selecting record from model in rails, if no specific setting, Rails will directly use the plurals of model name as the table name to do SQL query. For example, We select the last record in City model, and Rails will use cities as table name to do SQL query in database.

class City < ApplicationRecord
end
City.last
City Load SELECT `cities`.* FROM `cities` ORDER BY `cities`.`id` DESC LIMIT 1

If we want to load specific table when calling the model, we could clarify the table name in model. For example, if we want to load table tw_cities when select record form City model, we could put self.table_name = 'tw_cities' in City model, and Rails will use tw_cities as table name to do SQL query in database.

class City < ApplicationRecord
self.table_name = 'tw_cities'
end
City.last
City Load SELECT `tw_cities`.* FROM `tw_cities` ORDER BY `tw_cities`.`id` DESC LIMIT 1

If we have many tables have same prefix in their name, we might need to clarify the table name in each models. For example, if we have tables tw_cities, tw_country, tw_town in database, we might need to put self.table_name = .. in model City, Country and Town, so that Rails could load the exactly table when calling the model.

class City < ApplicationRecord
self.table_name = 'tw_cities'
end
class Country < ApplicationRecord
self.table_name = 'tw_countries'
end
class Town< ApplicationRecord
self.table_name = 'tw_towns'
end

But putting self.table_name = .. in each model is tedious, and against Rails Principle: Don’t repeat yourself(DRY). To improve the code, we could use table_name_prefix . The table_name_prefix method description :

Accessor for the name of the prefix string to prepend to every table name. So if set to “basecamp_”, all table names will be named like “basecamp_projects”, “basecamp_people”

from table_name_prefix api doc

After reading the description, we know that table_name_prefix could add prefix to table name, so first we could create a module TW and setting a table_name_prefix to prepend tw_ to table name when using this module.

# app/models/tw.rbmodule TW
def self.table_name_prefix
'tw_'
end
end

And setting the City, Country and Town model with namespace TW

# app/models/tw/city.rbmodule TW
class City < ApplicationRecord
end
end
# app/models/tw/country.rbmodule TW
class City < ApplicationRecord
end
end
# app/models/tw/town.rbmodule TW
class Town< ApplicationRecord
end
end

Then we could try to select record from City model. Now we need to call the model with namespace like TW::City The query result as below shows that Rails is automatic add prefix tw to the name of table cities

TW::City.last
TW::City Load SELECT `tw_cities`.* FROM `tw_cities` ORDER BY `tw_cities`.`id` DESC LIMIT 1

When calling the TW::Country , we could also see that Rails automatic add prefix tw to the name of table countries

TW::Country.last
TW::Country Load SELECT `tw_countries`.* FROM `tw_countries` ORDER BY `tw_countries`.`id` DESC LIMIT 1

If there is a tw_streets table appear in the future, we could easily add a Street model with TW namespace and select record through this model conveniently.

# app/models/tw/street.rbmodule TW
class Street< ApplicationRecord
end
end

To summarize, implementing table_name_prefix and namespace in Rails model is an useful way to organize models, especially for most of the tables related to the models with the same prefix in their table names. Furthermore, using table_name_prefix and namespace could help us not to repeat ourselves in our code which accords with the spirit of Ruby on Rails.

Reference

--

--

icelandcheng

Programming Skill learner and Sharer | Ruby on Rails | Golang | Vue.js | Web Map API