Ruby on Rails: Using table_name_prefix and namespace to organize models
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
endCity.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'
endCity.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'
endclass Country < ApplicationRecord
self.table_name = 'tw_countries'
endclass 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.