Trying to write a rails method to count the rows in a table.
The twist: I want to do it in such a way that I can call the method from any object and it will automatically determine the name of the table to count the rows from.
Basic outline of the flow … I want to use Rails Way to identify the table & count the resulting table name’s rows.
To do so I need the name of the model. As my test object, I cleverly naming it
2.3.1 :040 > anObject = Player.first Player Load (2.4ms) SELECT "players".* FROM "players" ORDER BY "players"."id" ASC LIMIT $1 [["LIMIT", 1]] => #<Player id: 1, screenname: "Serena Mitchell I", motto: "Wyaaaaaa.", country_id: nil, created_at: "2017-09-01 12:52:27", updated_at: "2017-09-01 12:52:27">
Rails has several definitions which hold that information in various states. I chose to use
2.3.1 :043 > anObject.class => Player(id: integer, screenname: string, motto: string, country_id: integer, created_at: datetime, updated_at: datetime)
When we look at this, it’s more information than we need. The Rails Way is to call the
.name method out of the class method …
2.3.1 :046 > anObject.class.name => "Player"
As a bonus
.name gives us access to
.constantize which is the goal.
2.3.1 :048 > anObject.class.name.constantize => Player(id: integer, screenname: string, motto: string, country_id: integer, created_at: datetime, updated_at: datetime)
Now we can put
.constantize to search all the Rails app’s constants …
2.3.1 :050 > anObject.class.name.constantize => Player(id: integer, screenname: string, motto: string, country_id: integer, created_at: datetime, updated_at: datetime)
… which when proceeded by the
.class.name will give the activerecord model as an object which we can then
.count against …
2.3.1 :052 > anObject.class.name.constantize.count (0.8ms) SELECT COUNT(*) FROM "players" => 46
At this point
.class.name.constantize should net us what we need, so I wrap it in a method for easy reuse …
# gets name of constant to get a count of model def row_count(ar_object) ar_object.class.name.constantize.count end
This of course isn’t perfect, if ever you had an conflict in the naming scheme, scope issues or an orphaned object from the inheritance tree, the
.constantize search up the object inheritance tree would fail even though your object exists.
Note there is another way, that if you are only doing ActiveRecord objects works too … Link. My example is slightly more generic example as you can use it to find other types of objectives – though you can’t use the count method with most of them.
The reason you would use it, is that it’s more self documenting, thus more in line with the Rails Way ….
# .model_name.name is basically the same as .class.name for this purpose ar_object.model_name.name.constantize.count
My studies from other authors which I found helpful, in no particular order …
- Failure points & discussions for constantize – Link
- Implementing in a custom module from Stackoverflow – Link
- Implementing the constantize lookup in depth & use – Link
- Safelty constantize in forms, aka don’t – Link
- Metaprogramming & testing with constantize – Link