You can manufacture your own cheerleader to small affirmations all developers need. Let’s look at how you can create a small application hosted on that sends text messages to developers that might appreciate a little encouragement. Heroku The app allows users to sign up for messages, get encouraging texts (such as "You are not your failing test suite" and "You're bigger than your bugs") once a week, and then stop the messages if the users no longer want to receive them. We’ll build the app using Ruby on Rails, Postgres, and the Twilio API, and we'll use Heroku pipelines and Heroku CI to run our tests and manage our deployment. Prerequisites First let's walk through what you'll need to get the app running. This is an intermediate-level tutorial, which may not be suitable for complete beginners. To follow along, you should: be comfortable writing and have it installed Ruby on Rails be comfortable using the terminal (or IDE, though I’ll be referring to a terminal in this tutorial) have installed Bundler have installed Postgres have installed ngrok You’ll need: a (the free account is fine)a (the free account is fine for hosting, but we'll also use Heroku CI and scheduler, which has a cost) Twilio account Heroku account Setup First we need to set up Ruby, Postgres, and Twilio. Rails & Gems I’ve provided a which you should clone to your local directory. To get started, run bundle install. starter project Postgres If you’ve never run Postgres on your machine (or you’ve stopped it), you’ll need to start the process by running . If you get any errors, check out the . postgres -D /usr/local/pgsql/data PSQL start-up guide You may also need to make sure that your database for the project has been created. To do this, you’ll need to run rails db:create to create the test and development databases. Twilio Follow the prompts to create a new project on Twilio and when you’re done, you’ll see your dashboard: On the left-hand side, you want to click the three dots in the circle and choose Programmable Messaging. I won’t go into all the details of getting set up on Twilio, as they have a great that does just that. The important thing to make sure you do is get a phone number as the guide prompts you to do. walk-through guide ENV Next we need to connect our app to our Twilio account. In your application, create a .env file at the root of your file structure and add the following to it: You want to make sure you add this file to the .gitignore. That way, you avoid checking sensitive information into git. Models & Data There are three models we’ll need for this app: Developers (our users) Affirmations (the messages we send) SentAffirmations (keep track of if we've sent the affirmation to each user) Let's take a detailed look at each one. Developers These will be our main users. Usually for user objects, I’d use something like to help manage authentication; however, that’s overkill for what we need. So we can simplify things by running: devise rails g model Developer phone_number:string confirmed:boolean uuid:string This is the bare-minimum data that we need to create our developers. The will be used to send users messages, is needed to get their confirmation for consent to store their details, and is a unique, difficult-to-guess identifier. phone_number confirmed uuid Once your migration file looks as you'd expect it to, run rails db:migrate. Then, in your developer model you want to add the following: We add a validation to the field to make sure there’s always one when a developer is created. We also want to add a scope so that we can easily access confirmed developers. phone_number We also want to ensure that a gets generated when a developer is created. We can write a test to check this. In spec/models you should see a file called developer_spec.rb. This is where you’re going to write this test: uuid This small test confirms that, when we create a developer, the uuid isn’t nil (we can then assume that the developer has a ). In your terminal, run rspec spec/models/developer to run the test. It should fail. uuid To make it pass, we’ll need to add the following code to our model: is a to which we can send methods to be invoked. In this case, we’re sending our private method . It’s private so that only this object has permission to invoke it. Ruby gives us the SecureRandom class, which we can use to call the handy uuid method that creates uuids for us. is the instance of the class. Using our test as an example, would be since is an instance of Developer. So we’re setting the on self to be whatever gives us, then we’re invoking that method right before the object is created. If you’re new to callbacks, roughly this is what’s happening: before_create Rails callback generate_uuid self self d d uuid SecureRandom.uuid Now when you run rspec spec/models/developer_spec, your tests should pass. Affirmations These are the messages we’re going to send out. The migration command you want to run is: rails g model Affirmation body:string To keep things simple, we only need the body for the affirmation. Run the migration once you’re happy with the file. In the Affirmation model, make sure that you validate the presence of the body by adding: to the top of the file. validates_presence_of :body Sent Affirmations This will act as a join table between Developers and Affirmations, so that we can keep track of which developers have gotten which affirmations. rails g model SentAffirmation developer_id:integer affirmation_id:integer sent_at:datetime Once you’ve checked that your migration file looks as you expect, run the migration. Here, we also want to set up the following relationships: Make sure the right file has the right relationship. Controllers Now let's look at the controllers. We'll need two: one for Developers and one for Affirmations. Developers Controller The developer controller is going to be the longest one since it handles the sign-up process. We’re also going to deviate from convention a little; there won't be any views for our controllers. We'll also create some custom endpoints for this controller. First let’s run rails g controllers Developers. This will give us the developers_controller.rb file, where we want to add the following to the very top of the file: skip_before_action :verify_authenticity_token This will remove the CORS authentication so that we can receive params from outside the application, i.e. Twilio. From here, we want to add the following: Let's look at the interesting parts of this code. will be the endpoint we use to receive the texts from our developers which Twilio forwards to us in a webhook. Here, we want to check the body of the request to guarantee we call the right method. In the config/routes.rb file, add so that we have a defined route and can add it as a webhook in Twilio. To do this, you’ll need to run in your terminal for the appropriate port number where your rails server will be running. For me, that’s 3000 so it’d be . This will give us a forwarding host. receive get 'twilio/receive', to: developers#receive ngrok ngrok http 3000 Add this host to your config/application.rb with . In Twilio, you’ll need to click the three dots in the Twilio menu and select Phone Numbers. Doing so should show you a page with your active numbers. Select your number and you’ll be redirected to a page that allows you to configure the number. If you scroll down to the Messaging section, you’ll see the input for the "A MESSAGE COMES IN" webhook. There, you want to add . This will enable Twilio to send the data that reaches the webhook directly to your local app. Use this to test the delivery of texts as you continue to build. config.hosts << '<YOUR HOST>.ngrok.io' <YOUR NGROK HOST>.ngrok.io/twilio/recieve will create our developer object/record using the phone number in the params. When the developer is created, we’re using the Twilio TwiML to send a confirmation text to the developer. Within the text, make sure to include the url for their confirmation link within the text string. The makes sure we render the correct file format which is sent to the Twilio API. create #{preconfirm_url(dev.uuid)} render xml: twiml.to_xml finds and deletes a user should they want to be deleted. Since phone numbers may be less unique than uuids, we could tighten this process by using to find developers. But for now, this is fine. delete uuid just acts as a GET placeholder for confirm. In the routes file, add the corresponding route This will allow us to set and collect the uuid as a param and also use as we’ve given it a name. preconfirm get: 'developers/:developer_uuid/confirm', to: 'developers#preconfirm, as: 'preconfirm' preconfirm_url is a private method that updates the confirmed field when a developer clicks the link in our text. It also renders a plain-text confirmation message in the browser. Add the matching route to the routes file. Notice that it’s a PATCH HTTP method. confirm patch 'developers/:developer_uuid/confirm', to: 'developers#confirm' Affirmations Controller Our affirmations controller is going to be simpler by comparison since we only need two methods and endpoints. First, let’s create it: rails g controller Affirmations. We’re also going to be breaking Rails convention here, since we don’t need all the endpoints and also want to include a static page here too. Let's look at this code. will act as our root path and just renders the static HTML page. In the routes file, you’ll first need to add and then, in views/affirmations, you'll create a HTML file called landing.erb.html with some markup you want people to see when they visit . landing root affirmations#landing / instantiates an affirmation which will be available to us in the view. Similar to the landing action, you’ll need to create a view, but this time it’ll be a form with space for a flash notice: new creates an affirmation, then redirects to the new affirmation path with a success notice. create is the private method that whitelists and accepts the correct params. We pass it to in the create method. affirmation_params Affirmation.create Add to the routes file to ensure you’ve got the correct endpoints. resources :affirmations, only: %i[new create] Lib, Task & Job Composing and sending the affirmation text is going to happen in a lib file, task, and job. Rake is a library that allows developers to create and manage tasks. rake First, we’ll create the lib. Lib The affirmation text should be a small self-contained class. This is where we’ll be using a bulk of the Twilio API. Before we get started, we want to make sure the lib folder is auto loaded for when the project starts up, so make sure your config/application.rb file has . Now in the lib folder, you want to create an affirmation_text.rb file. This will be our class for composing the affirmation text. config.autoload_paths<< Rails.root.join('lib') will set our client to be the Twilio client, to which we’re passing the environment variables we defined earlier. initialize takes the developer’s phone number and an affirmation. The Twilio client gives us which allows us to dynamically create SMS messages with our own values. messages messages.create Job Instead of sending the messages as we call the method, we actually want to put them in a job queue. By using a job queue here, the server can still accept incoming requests without having to wait for the text to be sent. We can create a job by running rails g job . This will give us a send_affirmation_job.rb file in app/jobs. In there, we want to do a few things: SendAffirmation Let's walk through this code. First, we want to define the queue we're using by including at the top of the file. queue_as: default is where we’ll tell it what to do when the job is run. It accepts and objects which will be used to send the text message. Since we don’t want to call the actual Twilio API when we’re testing, we can create a mock object. The code checks for the Rails environment. If it’s a test environment, it uses the mock method, if not, it uses the production method. deliver developer affirmation calls the lib we created in the previous step, which then calls the real Twilio API endpoint. send_prod calls our mock object. send_test is the mock object, with a message method to mimic . MockAffirmationText AffirmationText We can also write a test for this job. In our spec/jobs/ you should see a corresponding job file. In that job file, add: Given that we have some test data (which is what and are) and we’re using the test queue adapter, when we call a job should be queued. confirmed_dev affirmations SendAffirmationJob.new.deliver(confirmed_dev, affirmations.first) Task Because this will be run on a scheduler, we want to make a rake task that’ll be called at various intervals. In lib/tasks, create a rake file called send_affirmation_task.rb. Your rake file should look like this: This will allow us to call rake when we need to. In this block, we’re using the count to create an offset so that we can pick a random affirmation to send. Then for all the confirmed developers ( comes from our previously defined scope) we trigger the job and create a to keep track of our affirmations. affirmation:send_text confirmed SentAffirmation Heroku For deployment, we’re going to use Heroku. Heroku is a Platform-as-a-Service (PaaS) provider that makes it easy to deploy and host applications. Using Heroku keeps us from worrying about the details of hosting, building, scaling, etc. We'll use Heroku pipelines to create our staging and production apps, and CI to run the tests before each deploy. First, we want to make sure we’ve got an app.json file at the root of our project. Mine looks like this: You’ll need to make sure that the database cleaner environment variables are set so that the tests run properly on Heroku CI. You’ll also need to make sure you have a Procfile at the root of your app. The allows us to set the necessary commands for running our web and worker processes. It also allows us to decide what command we should run on each release of the app: Heroku Procfile Push this up to your GitHub repo. In your Heroku account, we'll create a new pipeline. This pipeline will allow us to manage the different environments (i.e. staging and production) for our app. Click New in the right-hand corner and then choose "Create new pipeline". Follow the prompts and connect it to the correct GitHub repo. Once everything has been created, your tests will run in the Tests tab and should look like this: Now we can create our staging and production apps. In Pipeline under staging and production, you’ll see the option to "add app". Click this and create a new app under each. Once this is done, we'll also use the Heroku UI to provision a database for each and a scheduler instance for the production app. You do this by clicking on the app name > "Resources". In the search box search for "Heroku Postgres" and "Heroku Scheduler". Even though you've provisioned the databases for each app, you still need to run the migrations. So for each app, go to More > Run Console In the modal that appears, run . Remember to do this for both your staging and production apps. rake db:migrate To configure the scheduler, create a scheduled job that runs the rake task we created, so which should look like: rake affirmation:send_text For each of the apps, we want to enable automatic deploys when the CI passes. The arrows on the right-hand side of the app components in the Pipeline will show more options. For example: You want to click "Configure automatic deploys" which will show this modal: Ensure that "Wait for CI to pass before deploy" is checked, then hit "Enable Automatic Deploys".’ Now whenever you hit "push to master", your tests will run. Once they pass, your app will be deployed. And because we’re using the Heroku to manage our migrations, they’ll also run automatically with every release. release phase The last thing you want to ensure is that your environment variables are set up properly. We don’t want to add the secret variables to our app.json since that would make them public. But in the settings for each of your staging and production apps, you can add config variables, so set the variables we defined in our .env here too: For the staging app, the variables should be the same as in our .env. But for the production app, you want to make sure that you’re using the production Twilio SID and Token which you can find in your Twilio account. The App in Action Now we're ready to run the app! Let's see what it looks like in action: Notes on Costs You can host basic apps on Heroku for free. However, Heroku CI costs $10 a month to use Heroku Scheduler has a free tier, but the dynos it uses to run are only paid dynos, so you’ll have to pay for the usage costs of those too. Twilio gives you a free $20 to test with, however you'll need to top up your account when you move to a production environment. Conclusion I've used Heroku's pipeline and CI in other production apps, but in those places everything was already set up. I've always found this aspect of Heroku a bit intimidating, but creating this fun little app allowed me to get familiar with the features, particularly the CI. There's still some work to be done to move this app to production. For example, a moderation feature is necessary to stop people from submitting weird affirmations, and some type of limitation on the texts would be good to limit costs. There's a lot of scope to play around with, ! so have fun Also published on: https://dev.to/lolaodelola/you-are-not-your-failed-test-suite-and-other-affirmations-an-app-on-heroku-db9