Potpourri of head scratchers

These are all minor but have caught me head scratching.

  1. Action Cable Documentation (I haven’t been able to get my head around it. Nothing specific but its a nice extension I want to use but I don’t understand how it works and none of the tutorials I’ve tried have worked for me either.) Maybe revamp the documentation?
  2. Model.column_names returns a reference not a copy. I created an issue by pushing or deleting items from this without realizing it was not a clone or a dup. This is super minor except for one key thing. Error caused by this appear very far away from the code where this happens, usually when creating records while importing (as is my case). Consider adding a ! bang to the end? Or at least improving the present documentation to make it clear it returns the actual property and not a copy of it.

Present documentation:

**column_names** () Returns an array of column names as strings.

  1. The many-to-many relationship ( has_and_belongs_to_many w/ join table) expects a very specific name of the join table. I created the join table but set the name of the table on the migration, and then couldn’t understand why this relationship didn’t work. Took me a while to realize that I’d named it in singular and Rails was expecting it in plural. So even though the tables were tied in the db, Rails just was confused by not finding a very specifically named table. This specificity is not mentioned in the documentation.

Do you feel up to updating the documentation for 3?

For 2, that seems like an interesting bug trap. @tenderlove or another maintainer – are there likely to be perf implications if .column_names returns a dup? If so, is it possible to have a public API with a dup and a private API which returns a reference?


We got to be careful returning a dup there are so many weird and wonderful ways it can be used, maybe it is a 200 column table.

I do wonder though why column_names is not a frozen array, the column names themselves are already frozen.


I’m not sure I get #3. Doesn’t the documentation for create_join_table clearly show the table names being plural. And Rails in general always uses plural for table names as a convention.

1 Like

Concerning 2, it makes perfect sense to freeze them. I’ve submitted a PR: Freeze many read only ModelSchema properties by casperisfine · Pull Request #39463 · rails/rails · GitHub


Concerning #2, Eric’s concerns: That is not where the issue is. Yes create_join_table will create the correct name but allows you to override the name of the table with the name option. The problem is that the relationship documentation doesn’t say it needs that specific name for it to work. So say in my case you’ve got two tables members and workshops and need a join table between them. The perfect name for this table would be participants, the members that are in a workshop but do that and the many-to-many relationship will not work, not only that the error is not clear that that is what is happening. This is a head-scratcher because the db knows the relationship, but Rails does not. This is hard to trouble-shoot because it is not clear that renaming this table will break the relationship on Rails. BTW, after trying participants and realizing maybe it needs a name with the two tables, I changed the name to something more like what rails would make it except I named it singular instead of plural and that took me forever to figure out. In a sense this many-to-many relationship depends on Rails naming the table automatically.

1 Like

I’m probably just not following but if you are not using the rails convention and naming your join table participants wouldn’t you use the :join_table option to match with the table name you created?

This naming (and the need to decorate the join in some manner, say for example what “kind” of membership is this), leads you to the recommended pattern of has_many through:. The classic “dumb join table” of has_and_belongs_to_many is not outright deprecated, but it is somewhat discouraged if you read the docs. Even if I don’t have any specific details to add to the join yet, I often find myself writing application this way because I remember the many times I have needed to add some later, and how much work it is to convert from the old-school relationship to the new.


It sounds like it’s not discouraged hard enough.

I think this will be a hard one to deprecate, because changing legacy databases is more difficult than changing legacy code, but maybe it’s time to deprecate has_and_belongs_to_many.

1 Like