In Part 6 we fixed a minor issue with our change email functionality. This leaves us with only 1 issues left from the list of tasks we compiled in Part 4.
- Update our sign-up functionality to prevent new sign-ups.
So this is what we’ll be working on today.
Getting started
As mentionned before, I’m not sure this series of posts is really a “follow along” type of series, but it is possible.
If you’ve been following along, you can continue with the code from part 6. Or you can clone the code as it stood after part 6.
Clone the Repo
If cloning the code from GitHub:
Terminal
If getting the code from GitHub, we also need to repeat our steps to set our local Ruby version and run bundle install
.
Terminal
Terminal
We’ll also need to copy over the configuration file we created in part 6.
Terminal
We’ll need to set our Google OAuth keys as eventually we’ll be manually testing that our changes work both for our custom authentication and for Google OAuth.
/config/heroku_env.rb
And with that, we are good to go.
Today’s objective
So today we want to update our code to prevent new users from signing up to the application, kind of a strange requirement right?
Why do we want to limit registrations?
Why are we doing this? Well we are using a Heroku managed Postgres hobby instance and we want to keep our data below 10k rows because we are cheap!
So as long as we stay below 10k rows we don’t have to pay anything for the instance. Therefore we don’t want anyone else using the application and stealing some of that valuable database row real estate 🙄.
The approach we’ll take
We have a number of options as to how we could accomplish today’s task:
- Rip out the sign-up code altogether.
- Comment out / circumvent the current sign-up code to prevent sign-ups.
- Turn sign-ups on or off based on a configuration setting.
I think it is pretty obvious that the last option is the best. Ripping out our sign-up code altogether would mean we’d completely lose the sign-up functionality. Commenting out or otherwise circumventing the sign up code is better than just ripping it out, but would still mean we couldn’t sign up a new user anymore without reverting the change and re-deploying the application. Either of the first two approaches would make testing etc. awkward. So the configuration setting approach is definitely the right one.
Creating a branch for our fixes
Now that we’ve decided on our approach, we’ll start off by creating a new branch.
Terminal
And now onto some code!
Restricting sign ups
We’ll want to update the sign-up process both in our controller code and in our user
model. We never want to rely strictly on our front end to enforce a limitation, we also want to restrict things on the back end. That way we don’t need to worry about a tricky user circumventing our UI restriction by sending a request to the back-end directly.
Updating our code
Let’s start with the user
model.
Updating the user model
We are going to add a before_create
filter to our model, any before_create
filter that returns false will halt the creation of a new model object. Therefore this fits in very nicely with what we are trying to accomplish.
/app/models/user.rb …line 34
Our new filter calls into a save()?
method which we’ll need to create.
/app/models/user.rb …line 248
Our new method checks an environment variable called registration_locked
, and if the value of the variable is true
, the save will be halted.
We also need to check our environment variable when creating a new user for an OAuth authentication, so a small update to the create_with_omniauth
method is also required.
/app/models/user.rb …line 274
We’ve just wrapped our main logic within an if
clause where we check our environment variable.
Let’s add some tests to our user_spec
to make sure our save?()
method is doing what we expect.
Updating the user_spec tests
We’re going to be explicitly setting registration_locked
to true
in some of our new tests, so we’ll want to make sure it is always set back to false
before any of the existing tests run, otherwise they are sure to fail. Therefore the first thing we’ll do is to add a statement to our top level before
block.
/spec/models/user_spec.rb
Simple, we just set the lock to false
so that user saves will still occur for our existing tests. Now let’s add two new tests, one just to make sure save still works (although we likely already have that scenario covered) and one to ensure we don’t save a user when registrations are locked. We’re using a before_filter
in our implementation so we’ll add the tests to the describe "filters"
section.
/spec/models/user_spec.rb …line 58
Pretty simple, one test to check the user is not saved, one test to check the user is saved.
If we run our tests, everything should be passing.
Terminal
Perfect! Let’s move onto our controller code.
Updating the controllers
We need to change both the users_controller
and the sessions_controller
, lets start with the users_controller
.
Updating the users controller
Currently the create
method of our users controller looks like:
/app/controllers/users_controller.rb
We need to add a tiny bit of logic to take into account our new environment variable:
/app/controllers/users_controller.rb
We’ve added an additional else clause that checks if registrations are locked down. If they are we display a message on the sign in page and don’t save the new user object.
Notice we are using a constant for our registration_locked
message, i.e. alert: t(:registration_locked, scope: 'flash_messages')
. We’ll need to add the constant to en.yml
.
/config/locales/en.yml …line 16
We can now add some tests for the controller.
Updating the users_spec tests
We already have a section in our test for sign up
, we’ll add our new tests to the existing sign up section.
First off however, we’ll need to add a global before
block to our test as once again we’ll be monkeying with the registration_locked
environment variable and we’ll want it to be reset before each test.
/spec/requests/users_spec.rb
Simple enough, now onto our tests:
/spec/requests/users_spec.rb …line 217
Let’s run the tests.
Terminal
And we get a failure, what is up with that! Looking at the test it is another one of those annoying email tests that failed in a few of our other test suites.
Let’s run it by itself.
Terminal
Still fails, we see the email in the log\test.log
:
So I am just going to ignore this test like we did with the other email tests… it’s not a great approach, but it’s what we’re going to go with for now.
/spec/requests/users_spec.rb …line 328
Let’s run our full test suite and see where we are at.
Terminal
Fanatastic, our tests are passing so this means we’re finished with our coding for the users_controller
. Now we need to make a small change to the sessions_controller
as this is where user’s are created when signing in via OAuth.
Update the sessions controller
/app/controllers/sessions_controller.rb …line 28
We’ve added an if user.nil?
clause as when a new user attempts to login via OAuth when registrations are locked, nil
will be returned from the call to from_omniauth
.
That’s it for coding! Onto setting up our configuration.
Configuring the environment variable
When it comes to setting our configuration on production we’ll be using the Heroku CLI and the config:set command, i.e.
Terminal
For our development environment, we’ll use our heroku_env
file however. So first let’s update the template file.
/heroku_env.rb.template
And then the actual configuration file.
/config/heroku_env.rb
And that’s all there is to that!
Manually testing our change
Before wrapping up for the day, let’s manually test out our change. We’ll start up the rails server.
Terminal
And then attempt to sign-up, first via Google.
Clicking the link yields:
Now if we try our custom authentication.
We also see our registration locked message.
After the above I also ran thru a quick test and ensured registration still worked when the environment variable was set to false
… all was good, so we’re done for the day!
Let’s wrap up by merging our changes into our refactoring branch and removing our current working branch.
Terminal
Summary
That’s it for our code changes! All that’s left is to perform a final test, merge our changes into our master branch and deploy to production. That’s what we’ll get after next time!
Thanks for reading and I hope you enjoyed the post!