How to add a new action to the existing controller?
When you repeat the generate
command with another method's name, you can skip overwriting the existing controller and it's test implementation. That will automatically add the route and create a view. After that you have to add the method manually to the controller because that action didn't touch the controller file.
Rails 6.1 additional info is in the comments below.
Example:
one method called new
was already created in the controller when it was initially created:
$ rails generate controller Person new
... successfully created the controller, it's route and view ...
when trying to add a new method:
$ rails generate controller Person all
Running via Spring preloader in process 28648
conflict app/controllers/person_controller.rb
Overwrite ../app/controllers/person_controller.rb? (enter "h" for help) [Ynaqdh] h
Y - yes, overwrite
n - no, do not overwrite
a - all, overwrite this and all others
q - quit, abort
d - diff, show the differences between the old and the new
h - help, show this help
Overwrite ../app/controllers/person_controller.rb? (enter "h" for help) [Ynaqdh] n
skip app/controllers/person_controller.rb
route get 'person/all'
invoke erb
exist app/views/person
create app/views/person/all.html.erb
invoke test_unit
conflict test/controllers/person_controller_test.rb
Overwrite ../test/controllers/person_controller_test.rb? (enter "h" for help) [Ynaqdh] n
skip test/controllers/person_controller_test.rb
invoke helper
identical app/helpers/person_helper.rb
invoke test_unit
invoke assets
invoke coffee
identical app/assets/javascripts/person.coffee
invoke scss
identical app/assets/stylesheets/person.scss
def hello
@hello = "hello"
end
def goodbye
@goodbye = "goodbye"
end
then in /config/routes.rb
get 'foo/hello' ## foo is the name of your controller
get 'foo/goodbye'
Remember to create the views too:
views/foo/hello.html.erb
that may look like this:
Say <%= @hello %>
views/foo/goodbye.html.erb
that may look like this:
Say <%= @goodbye %>
Add a new action is simple. All you have to do is add a method on your controller, like, for example:
# app/controllers/dummy_controller.rb
def get_back
logger.warn "It works!"
redirect_to :back
end
Now, to be able to access this action throgh a URL, you need to have a route for that. This is done in your config/routes.rb
file. You can add it as a hard route, like
get '/go_back', to: "dummy#get_back"
This is the simplest possible route. But you might want it to behave like a restful route. This is useful if you are doing an action over one or more models. So in your route file, you will have something like this:
resources :dummy do
collection do
get 'get_back'
end
end
This allows you to accept a get
method over a collection. You will have the helper dummy_go_back_url
, and to get to this page the url is /dummies/go_back
.
This is for acting over a collection of resources. If you are acting on one specific object, you should specify a member
action:
resources :dummy do
member do
get 'get_back'
end
end
Since a member action is for only one object, you will have a url like /dummies/123/go_back
. This automatically will set the variable params[:id]
in your controller to 123
, allowing you to easily fetch your object. Also, the helper method dummy_go_back_path
is defined, and received one object or id as parameter to generate the correct url.
These are the most simple routes you can have, but you can look in routing outside in from rails guides as a reliable source of information.