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:
"/rock", { :controller => "game", :action => "play_rock" }) get(
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:controller
in the route.Like all Ruby classes, the name must be
CamelCase
(notsnake_case
orSome_Hybrid
). So in this case, it will beGameController
.The class must be defined in a Ruby file that is the
snake_cased
version of its name. Rails will itself use the.underscore
method 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.rb
file extension).Finally, within this file, we define the class:
class GameController < ApplicationController end
We inherit from
ApplicationController
, which in turn inherits fromActionController::Base
; much like our models inherited fromActiveRecord::Base
viaApplicationRecord
.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
end
that goes with the Class; type it before you forget it.Move your
play_rock
action over fromapplication_controller.rb
into 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
.underscore
on a string containing the class name inrails console
to 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
.rb
file 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.