Apr 06, 2016
Table of contents:
Over the last couple of weeks we’ve been putting the various components together to creating a registration flow in Ruby on Rails.
In Part 1 we looked at building out the Model layer, which included the models for users, roles and assignments.
In Part 2 we added the register Form Object for encapsulating the process of registering as a new user and automatically getting assigned to the correct role.
In this final part we are going to be looking at adding the Controller and the View to allow the user to register with the application via the browser, as well as the Functional Tests required to assert that this functionality is working correctly.
In today’s tutorial we’re going to be flexing the application as a whole, rather than just concentrating on the individual “units” in isolation.
Something that we’re not going to test, but we’re going to need is a root route. So to prevent any weird errors later down the line, I’ll just add this now.
Open up the routes.rb
file under the config
directory and then delete the comments:
Rails.application.routes.draw {}
The first route we will be adding will be for the root of the application:
Rails.application.routes.draw { root 'home#index', as: :home }
This will pass traffic from the root of the application to the index
method on the HomeController
.
So to make sure that works we need to create a new file called home_controller.rb
under the app/controllers
directory:
class HomeController < ApplicationController
def index; end
end
We also need to add a view for this route. Under app/views
create a new directory called home
.
Before I do this I’m first going to switch out the template engine for Slim. To do that, add the following line to your Gemfile
:
gem 'slim-rails'
And then run the following command in Terminal:
bundle install
Finally you can create a new file called index.html.slim
under the home
directory:
h1 Welcome
Now if you run the following command in Terminal and then go to https://localhost:3000 in your browser you should see the welcome page:
rails s
In order for a user to register with the application, first we need to present them with an HTML form that they can submit.
So the first thing we need to do is to add the route. Open up the routes.rb
file again and add the following route:
Rails
.application
.routes
.draw do
root 'home#index', as: :home
get 'register', to: 'register#new'
end
This will direct GET
requests to /register
to the new
method on the RegisterController
controller.
So next up we need to create the RegisterController
. Create a new file called register_controller.rb
under the app/controllers
directory:
class RegisterController < ApplicationController
def new
@form = RegisterForm.new(User.new)
end
end
The implementation of the new
requires that we instantiate a new instance of the RegisterForm
Form Object from last week and pass a new instance of the User
model.
We also need to create a new view file that will generate the HTML form for this page. Create a new directory called register
under the app/views
directory and then create a new file called new.html.slim
:
- if @form.errors.any? ul
- @form.errors.full_messages.each do |msg| li = msg =
form_for @form, url: "register" do |f|
div = f.label
:email = f.text_field
:email div = f.label :password = f.password_field :password div = f.submit
"Register"
We now have everything in place to display the form in the browser, but to assert that this is the case, we can add the first Functional Test.
Create a new file called register_controller_test.rb
under the test/controllers
directory:
class RegisterControllerTest < ActionController::TestCase
test 'should get register form' do
get :new
assert_response :success
end
end
In this test I’m making a GET
request to the new
method of the RegisterController
and then asserting that the response is :success
. If you run this test you should see it pass.
bin/rake test test/controllers/register_controller_test.rb
As a final step of verification you can boot up the Rails server and go to https://localhost:3000/register to see for yourself.
When a user registers for the application, there are a lot of things that could go wrong. For example, they might enter an email address that is missing, invalid, or already registered.
When this happens we want the user to be redirected to the form so they can correct their mistakes. In this next section we will implement the code to make this happen.
First up I will add a test to assert that the request fails when the data that has been provided is invalid:
test 'should fail with invalid data' do
post :create, register: { email: '', username: '', password: '' }
assert_response 400
end
If you run the tests again you will see this fail because we have not created the route yet. I’m not going to step through each part of implementing this bit of functionality. If you want to see how the error messages guide you to what you should implement next I would encourage you to run the tests after each step of the following process.
First I’m going to add a new route to the routes.rb
file:
Rails
.application
.routes
.draw do
root 'home#index', as: :home
get 'register', to: 'register#new'
post 'register', to: 'register#create'
end
Next I’m going to add the create
method to the RegisterController
Controller:
class RegisterController < ApplicationController
def new
@form = RegisterForm.new(User.new)
end
def create; end
end
Next, I’m going to add a register_params
method to get the parameters from the request:
private
def register_params
params.require(:register).permit(:email, :username, :password)
end
Finally I will implement the create
method. First I will instantiate a new instance of the RegisterForm
Form Object:
@form = RegisterForm.new(User.new)
Next I will check to see if the request is valid by calling the validate
method on the Form Object and pass it the return value of register_params
:
if @form.validate(register_params)
else
end
If the request is not valid I will render the :new
method and set the HTTP response code to 400:
if @form.validate(register_params)
@form.save
redirect_to '/'
else
render :new, status: 400
end
The full controller will now look like this:
class RegisterController < ApplicationController
def new
@form = RegisterForm.new(User.new)
end
def create
@form = RegisterForm.new(User.new)
if @form.validate(register_params)
else
render :new, status: 400
end
end
private
def register_params
params.require(:register).permit(:email, :username, :password)
end
end
Now if you run the test again you should see it pass.
Now that we have failing registrations taken care of, we can write the code to deal with valid registration requests.
First I will write a test to assert that this functionality is working correctly:
test 'should register new user via html request' do
post :create, register: attributes_for(:user)
assert_response 302
end
If you run this test you should see it fail because the request is not being redirected correctly when the form is saved.
To make this test pass we can implement the successful branch of the if
clause inside of the create
method of the RegisterControlller
Controller:
class RegisterController < ApplicationController
def new
@form = RegisterForm.new(User.new)
end
def create
@form = RegisterForm.new(User.new)
if @form.validate(register_params)
@form.save
redirect_to '/'
else
render :new, status: 400
end
end
private
def register_params
params.require(:register).permit(:email, :username, :password)
end
end
If you run those tests again you should see them all pass!
Congratulations! You have now successfully implement the registration process of your Ruby on Rails application.
Over the last couple of weeks we’ve put into place everything we’ve learned so far including creating Models, Form Objects, Controllers and Views, as well as writing Unit and Functional tests where appropriate.
We’ve also covered a lot of the little details around building a Rails application and we’ve developed a workflow for building out the required functionality.
The registration process in this mini series has been purposely kept fairly simple. In a real world application you will probably have to deal with a whole load of extra requirements for any particular application.
But hopefully you have learned enough of the basics to confidently go on and build your own registration process for your own Ruby on Rails application.
You can see all of the code from today’s tutorial on Github.