- Update our sign-up functionality to prevent new sign-ups.
So this is what we’ll be working on today.
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:
If getting the code from GitHub, we also need to repeat our steps to set our local Ruby version and run
We’ll also need to copy over the configuration file we created in part 6.
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.
And with that, we are good to go.
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.
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
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
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
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.
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
Updating the users controller
create method of our users controller looks like:
We need to add a tiny bit of logic to take into account our new environment variable:
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
/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.
Simple enough, now onto our tests:
/spec/requests/users_spec.rb …line 217
Let’s run the tests.
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.
Still fails, we see the email in the
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.
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
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.
For our development environment, we’ll use our
heroku_env file however. So first let’s update the template file.
And then the actual configuration file.
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.
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.
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!