2.16 Addendum: Custom Controller Files
We don’t have to put all of our actions within the default ApplicationController file that comes included with any Rails app; we can add our own controllers, if we want to organize things a bit more. With an app of any non-trivial size, you’ll end up with hundreds of actions, and it can get unwieldy to put them all in one gigantic application_controller.rb.
Instead, we can change our route for /rock to this:
get("/rock", { :controller => "game", :action => "play_rock" })Now when a user visits /rock, they will see an error uninitialized constant GameController.
As we know, when Ruby says “uninitialized constant” it means “I can’t find that class”.
So, what’s going on here? When we said :controller => "game" in the route, we told Rails to look for a class called GameController when someone visits /rock.
All of the controller class names will end in
...Controller, and they will begin with whatever value we provided for the key:controllerin the route.Like all Ruby classes, the name must be
CamelCase(notsnake_caseorSome_Hybrid). So in this case, it will beGameController.The class must be defined in a Ruby file that is the
snake_casedversion of its name. Rails will itself use the.underscoremethod to figure out the name; we can try it ourselves inrails console:[2] pry(main)> "GameController".underscore => "game_controller"The Ruby file must be placed within the
app/controllers/folder. So, in this case, we create a file calledapp/controllers/game_controller.rb(don’t forget the.rbfile extension).Finally, within this file, we define the class:
class GameController < ApplicationController endWe inherit from
ApplicationController, which in turn inherits fromActionController::Base; much like our models inherited fromActiveRecord::BaseviaApplicationRecord.Our models inherited
.save,.where, and a bunch of other awesome database-related methods fromActiveRecord::Base; whereas our controllers are going to inherit a bunch of methods likerender,redirect_to, and a bunch of other awesome interface-related methods fromActionController::Base.Don’t forget the
endthat goes with the Class; type it before you forget it.Move your
play_rockaction over fromapplication_controller.rbinto this new class.Now, when a user visits the path /rock, the “uninitialized constant” error should go away and you should see a response as before.
If you still see the “unitialized constant” error, then:
- You named your class wrong; it must exactly match the value in
routes.rb, followed byController(singular), andCamelCase. - You named the file wrong. Try doing
.underscoreon a string containing the class name inrails consoleto figure out the correct filename. - You put the file in the wrong folder. It has to be within
app/controllers/. Not within, for example,app/orapp/controllers/concerns/. - You forgot the
.rbfile extension. - If you can’t find which of the above it is, try deleting what you did and paving over your work again from scratch. Sometimes you just can’t spot your own typos, and paving over is the best approach.
- You named your class wrong; it must exactly match the value in
You can make as many controllers as you like; in general, a rule of thumb is to have one controller per database table.