I’ve Got 99 Problems – but Deploying My Rails/Angular App to Heroku is No Longer One of Them:) PART 2

So where was I? Oh yeah, I left off at changing my problem js file extensions to ‘.es6’ so there would be no problem with new JS6 syntax. This definitely helped, but in it’s place sprung another problem. Only the images that were not hooked up to the database on my site were showing . So I used my noggin and realized that I never migrated my database to Heroku! DOH!

When I tried to run ‘heroku run rake db:migrate’, the migration kept aborting with this message:

PG::UndefinedTable: ERROR:  relation "users" does not exist

I definitely had a table called “users” so that didn’t make much sense. I did a little digging and found out that postgres (the database Heroku uses) does not like tables relating to other tables that have not been created yet. The table being created was referencing a table that was created on a later migration. I know it’s not a good idea to mess with the names of migration files, but I did anyway. Rails timestamps migration files, so I just had to change my “users” file timestamp to a date before the file in question.

So I tried the migrate command again and got the same error. Strange. My migration files had quite a few additions which later became subtractions. I decided that I only really needed three migrations for three tables. Since I had a good seed file which could recreate everything I needed, I decided to recreate only the migrations I needed. This would allow me to reset the database and start from scratch. I deleted the schema and development.sqlite3 files so there would be no references to the old migrations. Now I could recreate my database and schema file.

$ rails db:drop db:create db:migrate db:seed
// This will delete the entire database, losing all data
// recreate a new database and runs the migrations
// db:seed will seed the database from seeds.rb

I had a brand spanking new schema and database, ran my local server and everything was running smoothly. So I ran the heroku migration command again and got THE SAME ERROR!! WTF?!? After googling for a bit, it hit me. I didn’t push the new changes to heroku! Often times it is the simple tasks that one might forget to do that causes errors. Note to self: if you are banging your head against the wall, stop for a minute and think of the steps you would normally take. Save yourself some time and energy. The first change to the “users” migration file name probably would have worked if I just slowed down a little.

After trying to migrate to Heroku again, it worked! Now my site is up and running, and I’m feeling good! Hopefully this helps fellow programmers out there that get stuck – and have sore heads! As always, thanks for reading!

AngularJS: Filter – Behind the Scenes

AngularJS comes with a ton of built in features to help us out – meaning we don’t have to reinvent the wheel every time we want to do something. This makes it extremely easy to do things such as searching or filtering. However, sometimes it’s a good idea to check what’s going on under the hood, which can only help us in the end. These helpers are great, but if you’re knew to programming, they could stunt your growth as a developer. So let’s dive in.

I built an app called Medidate. It’s a simple (a lot of hours goes into simple!) single page app that keeps track of meditation sessions: the date, which kind of meditation, and the duration. It uses Rails as an API on the back-end and AngularJS on the front-end. I’m going to go over a sorting feature that could easily be implemented with Angular’s built in Filter helper. Here’s a Plunker with the easy way.

The Easy Way

Here’s some of the code…

    <div ng-controller="UsersController as vm">
      <div class="container">
        <div class="col-md-3 col-md-offset-9 dropdown-meditation">
          <div class="button-group">
            <select class="btn btn-default btn-md dropdown-toggle dropdown-text"
              ng-model="vm.option">
              <option value="" disabled selected>Sort Events By</option>
              <option value="date">By Date (Asc)</option>
              <option value="-date">By Date (Desc)</option>
              <option value="meditation.name">By Meditation</option>
              <option value="minutes">By Minutes</option>
            </select>
          </div>
        </div>
        <br>
        <div ng-repeat="event in vm.user.events | orderBy: vm.option">
          <p style="text-decoration: none">{{event.date | date: medium}} for {{event.minutes}} minutes &mdash;
        {{event.meditation.name}}</p>
        </div>
      </div>
    </div>

To give a bit of background, the information that’s being sorted here is an array of user events. The user has many events, which have the date, minutes, and a nested association of meditation, with id and name. This was all produced from an $http call to the back-end which was serialized into JSON by active model serializer – a very helpful gem for Rails.

Notice the dropdown and how we’re listing the options. The values of the options are bound to vm.options. All we have to do is declare vm.option = ” in the controller and when the dropdown is selected, vm.option will now be bound to the selected option. This will in turn set the filter in the ng-repeat. Notice the orderBy : vm.option that is declared in the repeat. This is the aforementioned built in magic of Angular. Whichever option is selected in the dropdown will change the orderBy option and effect how the list is ordered.

But what happens when you’re asked how it works. You know, like if someone asked you the what happens when you press the gas pedal in your car?  I don’t know, it just goes!

This is when it gets interesting. Getting your hands dirty.  Instead of using filter in the ng-repeat as above, we’re going to leave ng-repeat alone, with no orderBy filter! The hard work is going to be done in the controller. Check it.

The Hard Way

Here’s the  dropdown and ng-repeat…

    <div ng-controller="UsersController as vm">
      <div class="container">
        <div class="col-md-3 col-md-offset-9 dropdown-meditation">
          <div class="button-group">
            <select class="btn btn-default btn-lg dropdown-toggle dropdown-text"
                    type="button" 
                    ng-model="vm.selectedOption"
                    ng-change="vm.sortBy()" 
                    ng-options="option for option in vm.options">
              <option value="" disabled="" selected="">Sort Events By</option>
            </select>
          </div>
        </div>
        <br>
        <div ng-repeat="event in vm.user.events">
          <p style="text-decoration: none">{{event.date | date: medium}} for {{event.minutes}} minutes &mdash;
        {{event.meditation.name}}</p>
        </div>
      </div>
    </div>

In the dropdown above, ng-model is set to vm.selectedOption. Now whenever the user selects an option from the dropdown, the model is now bound to the option from ng-options. The options are declared in the controller which we’ll be taking a look at soon. The straw that stirs the drink is ng-change, which fires the vm.sortBy function in the controller. Let’s take a looksie.

.controller('UsersController', [function() {
      
      var vm = this;
      vm.sortBy = sortBy;
      vm.sortDate = sortDate;
      vm.sortMeditation = sortMeditation;
      vm.sortMinutes = sortMinutes;
      
      vm.options = ["Date (Asc)", "Date (Desc)", "Meditation", "Minutes (Asc)", "Minutes (Desc)"]

      function sortBy() {
        if (vm.selectedOption === vm.options[0]) {
          vm.sortDate();
        } else if (vm.selectedOption === vm.options[1]) {
          vm.sortDate();
          vm.user.events.reverse();
        } else if (vm.selectedOption === vm.options[2]) {
          vm.sortMeditation();
        } else if (vm.selectedOption === vm.options[3]) {
          vm.sortMinutes();
        } else if (vm.selectedOption === vm.options[4]) {
          vm.sortMinutes();
          vm.user.events.reverse();
        }
      };
 
// more code below

I like to bind my functions up top so I can see exactly what’s going on in the controller. This way I don’t have to search through hundreds of lines of code. Also, now we can just go ahead and write the functions as declarations, not expressions, which will save us from any hoisting headaches.

Like I said before, when the option is selected from the dropdown, that option is now assigned to vm.selectedOption and the vm.sortBy function fires. In the sortBy function, we’ll check to see which option was assigned to selectedOption and then fire a corresponding function to sort the user.events array. Here are the missing sort functions…

      function sortMinutes() {
        vm.user.events.sort((a, b) => parseInt(a.minutes) - parseInt(b.minutes))
      }

      function sortDate() {
        vm.user.events.sort((a, b) => (new Date(a.date)) - (new Date(b.date)));
      }

      function sortMeditation() {
        vm.user.events.sort((a, b) => {
          if (a.meditation.name < b.meditation.name) {
            return -1;
          } else if (a.meditation.name > b.meditation.name) {
            return 1;
          } else {
            let dateA = new Date(a.date);
            let dateB = new Date(b.date);

            if (dateA > dateB) {
              return 1;
            } else if (dateA < dateB) {
              return -1;
            } else {
              return 0;
            }
          }
// end of UsersController

Each function handles the data based on what the value is. Because the data in the user.events array are strings, we’ll have to convert them before sorting. The sortMinutes function is dealing with numbers which forces us to parseInt() the strings to integers. Same thing goes for the sortDate function, which we have to convert to a date before it can be sorted. Last is the sortMeditation function which takes the nested association – meditation – and sorts by name. Here we’re returning a negative 1 if the a is less, positive 1 if the b is less, and then instead of a zero if the names are the same, we’re using a sub-sort, which sorts by date.

Here’s a working plunker of the non-magic Angular filter. I think it’s cool to look under the hood sometimes and see what all the magic is about. You never know if you’re going to learn something new – I know I did! Leave a comment below if you have any questions. Thanks for reading!
 

 

 

Medidate: A Meditation App built with Rails and AngularJS

I’m just finishing up my new app. It’s a meditation app called ‘Medidate’, that keeps track of your meditations – the type of meditation, how long you meditated, and the date. You can also explore new meditation techniques.  I built it using Rails on the back end as an API and AngularJS on the front end. Since it was my first time using the two frameworks together, it was quite a challenge. I’m going to walk through some of the steps to get these two frameworks to play nice together and also show some cool modules that I used.

Rails as an API

First off, to get Rails set up as an API is easy-peasy. The necessary gem is ‘active_model_serializers‘ and after bundling we only have to do a few things to get up and running.The app has three models – user, meditation, and event. After setting up the models, to generate the serializers we run ‘rails generate serializer  <model name>’ in the terminal. Then we’ll set up our associations in each serializer. The User Serializer looks like this:

class UserSerializer < ActiveModel::Serializer

attributes :id, :username
has_many :events
has_many :meditations, through: :events

class MeditationSerializer < ActiveModel::Serializer
attributes :id, :name
end

end

Notice how the MeditationSerializer is nested inside the User. This allows us to dictate exactly what information we want from the Meditation model. In this case just the id and name will suffice. This is not a big app so this doesn’t matter that much. But in an app that is large and has a lot of information being retrieved from the database. Instead of getting every attribute of Meditation, we’re now only getting two. Much less information getting pulled from the backend. The Event and Meditation Serializers look pretty similar.

Next, on to the controllers. Here, we’ll have our CRUD actions render json from the serializers. Here’s the Events Controller:

Screen Shot 2017-03-13 at 9.09.13 PM

Pretty standard looking for a Rails Controller. You might’ve noticed that it’s namespaced as an API with version control. This will allow us to create new versions in the future without breaking something. Now on to Routes.

When creating the routes we have to remember about the name spaced controllers. Instead of the usual ‘resources :users’, now we have to nest the resource like so:

namespace :api do

namespace :v1 do

resources :users

end

end

We’ll do the same for events and meditations and add one more route for our root which will be:

root to: ‘application#angular_home’

And we’re good to go.

Setting Up Angular

Getting Rails and AngularJS to play nice was difficult at first. I went with Bower to install my dependencies for Angular. Installing wasn’t a problem, but when I tried to require the dependencies in the main ‘application.js’ file, the dependencies were not found. What to do?  I realized that when I installed the dependencies with bower, they were not being saved in the right place. In order for Rails to find the files, they have to be in the asset pipeline. That means they have to be in an ‘assets’ folder which are found in these places:

‘app/assets’, ‘lib/assets’, and ‘vendor/assets’

Angular dependencies should be kept in the ‘vendor/assets’ folder, so I moved the bower components folder there. Everything was good after I did this, however when I installed new dependencies with bower, they would wind up saving in a different place. After a little digging I found the culprit – the .bowerrc file. It basically tells bower where to save components when installing. Here’s what I had to do in .bowerrc:

{
“directory”: “vendor/assets/bower_components”
}

Now when installing dependencies from the command line, everything was saving to the correct folder!  One more thing –  add ‘vendor/assets’ to the gitignore file so all the dependencies are not pushed to github.

Authentication

There are many ways to authenticate these days. Since I was familiar with Devise, having used it a bunch in Rails, I decided to stick with it. Using the ‘devise‘ gem for Rails and ‘angular-devise‘ for Angular, it wasn’t too tough to get things moving. The hard part was keeping the user signed in after they were authenticated – persistence. I tried putting a currentUserSignedIn variable on the $rootScope, but on a page refresh, the rootScope gets destroyed, so that was a no go. I ended up using ngStorage, a cool little module that gave me what I needed. Basically, it gives you a storage variable that will be persisted throughout the app. Check out my other blog post here for more information on usage.

Toaster

I wanted to add some user interactivity to the app, you know, like pop ups when you submit a form. I ended up using AngularJS-Toaster. It’s pretty simple to use. After installing it with bower and requiring it in ‘application.js’, you only have to inject it in the main app module and the controller of your liking. Then you just pop it in to a function, like so:

Screen Shot 2017-03-14 at 3.01.08 PM

As you can see, the Toaster module gives us a few options. I only had the need for two of them: ‘success’ and ‘error’. ‘toaster.pop’ takes three arguments: the type of message (ie success), the title, and the message. I just used the title as you can see above. I was able to tweak the message colors and icons so they were more inline with my app. In my scss file I basically overrode the default icon like so:

Screen Shot 2017-03-14 at 3.08.30 PM

Now the icon for the success pop up is my very own and the app looks much more congruent.

Screen Shot 2017-03-14 at 3.35.51 PM

Before

Screen Shot 2017-03-14 at 3.39.45 PM

After

 

Conclusion

This app is not deployed yet, but if you want to check it out, go fork it from github. I learned a ton by building this app. Angular and I were definitely not friends before I started this app, yet slowly but surely we grew on each other.

AngularJS: Using $localStorage to Keep Users Logged In

If you are familiar with authentication, then you are should be familiar with sessions and web tokens. While the latter is the standard these days, sessions still have their place, especially when building small apps. The app I’m currently working on is using a Rails API with an Angular front-end. Since it was my first time attempting to use authentication with Angular, I used the tried and true Devise gem for Rails and Angular-Devise for Angular. Devise was fairly simple to set up and I had it working pretty quickly. Their documentation is pretty good as far as documentation goes!

I was saving my user info and their signedIn status in the $rootScope of my app which would make it accessible to all of my views and controllers. This worked well until a page was refreshed and my $rootScope was demolished along with all my users signedIn status. This is a good thing to know about Angular! The rootScope starts fresh on every page refresh. After reading up and doing some soul searching, I found a solution.

ngStorage to the Rescue

The ngStorage module allows you to store information that you want to have available during a session. After bowering or npm-ing, all you have to do is add ngStorage to your apps dependencies and inject $localStorage or $sessionStorage into any controller you need it in. Pretty simple. Now to use it, you have to pass $localStorage by reference to a hook under $scope or $rootScope, like so: $rootScope.$storage = $localStorage. Add this line to your controller and you have access to all the goodness that you would like to store there.

The basic usage would be to pass a boolean to your currentUserSignedIn variable on the $storage when they are logged in. Using Devises’ Auth.login function, you can then add the users status in the callback function.

Screen Shot 2017-03-06 at 10.01.13 AM

 

Ignore the toaster.pop (although check it out, it’s cool!) stuff going on and pay attention to the $rootScope.$storage line. Here we set currentUserSignedIn to true and have that information available in our views. Since it’s set on the $rootScope, we should have access to it throughout our app. Now on page reloads, we still have access to our users’ signed in status. Cooool!

I have a navbar throughout my views which uses its own controller. Since I used $rootScope.$storage I should have access to the users’ status. There was one occasion, however, where I would lose access to the $storage variable on a page reload. I wasn’t quite sure what was happening, but when I added $scope.$storage = $localStorage to my navbar controller, everything worked fine again. Don’t forget to inject $localStorage into the navbar controller. Now in the navbar html template, if we wanted to have a link to show “Log In” if the user is not logged in we could use a ng-hide directive as such:

screen-shot-2017-03-05-at-6-57-27-pm

 

If our user is logged in, we can simply change the hide to a show for a Log Out link:

screen-shot-2017-03-05-at-6-58-30-pm

When our user signs out we can reset our $localStorage or set the currentUserSignedIn boolean to false. We do this just like we did in the sign in function:

Screen Shot 2017-03-06 at 10.15.36 AM

Here we set currentUserSignedIn to false and our users session is complete. I’m definitely going to check out JWT Tokens next, but baby steps are good to take with these things. Thanks for reading!

 

 

AngularJS: We have an Error

If you’re like me and find AngularJS hard to understand, then debugging can be even more difficult. Since I’ve been running into them quite often, I’ve improved upon my abilities to decipher the cryptic errors that pop up in the console. Most of the time, these pesky errors are of the simple human variety: as in, you probably misspelled a word or forgot to add a dependency. In my case today, it happened to be loading my scripts in the correct order. Here’s the error I was receiving:

screen-shot-2017-01-25-at-2-39-47-pm

Lovely, right? Okay where to start. Well, of course now I know, but I’ll take you along through my thought process. First, I checked app.js to see if there were any typos. Nope, sorry sir, move along. Second, as you can see from the error above, the last line says PostService.js.15. So I’ll check out that file, and on line 15 the module is correctly stated. The only other place it could be (since my app is so small) is my index.html file. Let’s head on over there. My scripts were loaded as follows:

screen-shot-2017-01-25-at-2-51-46-pm

These were loaded just before the closing body tag. See anything troubling? Well, I have a service and a controller loading before my app.js file. So when the scripts are loading, my module hasn’t been created yet. Simple, yet frustrating. So just remember to load your app.js script before your other js scripts (and after your angular.js scripts). Oh Angular..some day we’ll be friends.

screen-shot-2017-01-25-at-3-18-47-pm

AngularJS & Rails: No Helpers:(

Angular is a front-end framework and is used for speed and asynchronous page loading (no page reloading on each request). Which means much of the helpers we rely upon in Rails are deemed useless. This can be hard to take for someone new to a front end framework like myself. But, alas, life must go on! The biggest obstacle for me so far is not being able to use the Flash Messages helper provided by Rails. What to do?

There are a few options out there on github that you can use. After trying a few different repos on Github which gave me a plethora of errors, I came across Toastr. It appealed to me right away because of it’s simplicity. I ran into one small bug (which was on my side), so I thought I might share.

The Set Up

screen-shot-2017-01-19-at-5-02-44-pm
First, to install Toastr, you can use Bower or npm. Next, copy the css and js files from the repo into your Asset Pipeline  – app/assets/stylesheets and app/assets/javascripts respectively. This will auto-rails-magically make the files available to use (as long as you //= require your trees *= in your application.js/css files). Now we can set up a factory in Angular.

The Chocolate Cheese Toaster Factory

screen-shot-2017-01-19-at-7-18-05-pm

Hey you…can you pass the butter, please?

Here we have set up a factory (we can just as easily use a service), which returns an object. Note that we also have access to other methods such as info and warning, but I only needed success and error for my project. When we call our toaster from a controller, we can give any text we’d like the user to see as an argument. I needed an error message telling a user that they couldn’t upvote a post more than once.


This Isn’t Going to Hurt, I Swear

We can then inject our toaster (factory) into any controller we’d like, then we have access to our success and error calls.

 

screen-shot-2017-01-19-at-8-20-51-pm
We’re injecting our toaster factory into our Main Controller. Now we can use it in any function we see fit. As I mentioned earlier, I needed to show the user an error if they tried to vote more than once on a post. By using a basic conditional statement with a some method on the array I could check for previous voters. I created a private function called voteChecker that checks the an upvoted posts user_id against the current_user $scope.user.id (I had to use inject the controller with Auth from the angular-devise gem for this).

screen-shot-2017-01-19-at-8-30-10-pm

By using the voteChecker function as the callback for the some method, we can check if any of the previous upvotes were from our current_user (I know, I know). However, the some method will return true if our array is empty, so we have to check that too. If the some method returns true && our upvoted_posts array’s length is not zero, then we have ourselves a two-timer and get to yell at them:) If, however, the challenge is passed, then we get to use our posts service (which I’m not going to delve into) to upvote our post. Very nice!

The Bug

I almost forgot! After doing everything above, I was getting a strange error:

TypeError: Cannot read property ‘extend’ of undefined

Crap! Well after a little Stack Overflowing it turned out that I was requiring jQuery after Angular in my application.js file. Once I put it before angular, everything was all good. NOTE – the same goes for if you’re including links or script tags referencing the angular and jQuery files from your application.html file. Well, all this toaster talk has made me quite hungry, so I think I’ll end here. If you ever need a flash message in your life and you’re using a front end framework, check out toastr!

 

Stumbling Through Angular: Routes!

AngularJS can be quite difficult to comprehend. Today, while trying to follow along Udemy’s Angular tutorial (hosted by Tony Alicea – it is great by the way!), I ran into some trouble with routing. Angular has built in routing that is very useful, but when things don’t work as you think they should, it can be frustrating. Every programmer in the world has been there. Although banging your head against the wall for a few hours can be quite fun, sometimes it’s best to go take a walk. When you come back, all of a sudden the problem is obvious. In my case, I was really trying to do something simple, but I just couldn’t get it to work.
screen-shot-2017-01-03-at-8-21-56-pm
Setting up the routing is fairly easy, once you  know the basic syntax of Angular. To the left is the file structure for my primitive app. I just wanted to have a main index page with two links. Simple right? Well a few hours later, yes…very. But if I can save anyone else a little time then it was all worth it. First off, we have to let Angular know that we want to use routing in our app. We can either use a link from Angularjs.org or we can download the node modules directly into our app, which I did. In both cases, we add it to our app with a script tag in index.html file. To download, in your terminal type:

‘npm install –save angular-route@1.6.1’

The numbers at the end represent the version of Angular you are running. If you’re not sure which version you’re running, open up package.json and you’ll find it in there.

Now we can add the script to our index.html file (it must be under your angular.js script!).

screen-shot-2017-01-03-at-8-39-31-pm

Note that these are all relative to my index.html file which is in the top of my file directory. Next, in app.js we let Angular know we want to rely on ngRoute. We do this in our module setup like so:

screen-shot-2017-01-03-at-8-32-02-pm

Here we are setting our module up and telling it to include ‘ngRoute’. Now we can use the routing capabilities. I set up two simple controllers to handle the two different links:

screen-shot-2017-01-03-at-8-50-42-pm

Here I’m using the array syntax which basically allows you to minify your files when you go to scale without any hiccups. But that’s for another blog post.  In the body of my index.html file I have two links and a div with a built in Angular directive.

‘ng-view’ tells Angular to look at the url screen-shot-2017-01-04-at-9-04-33-amand use the correct template that we set up with our routing. For this exercise I daisy chained all of my controllers and the like to my main module, but for bigger applications we’d have them in their own separate files. Now all we have to do is hook up our routing and we’re all set…

screen-shot-2017-01-04-at-10-16-54-am
So when we go to our main route, ‘/’, we’re expecting our ‘ng-view’ to summon up our main.html file with our $scope attached to our mainController. Welp, that didn’t work. I was getting a ‘404 (Not Found)’ error in my console. My main.html file couldn’t be found.

After searching stackoverflow.com for a  while I thought I found my answer. You can check out this stackoverflow exchange to see what I thought might be going on. Here’s the gist of it…

screen-shot-2017-01-04-at-10-50-12-am

So I tried a few of their solutions and also tried changing the templateUrl to no avail. After taking a much needed walk, I realized that I was giving the location of my html file relative to my app.js file and not my index.html file. So once I changed the templateUrl to reflect that, everything was groovy!

screen-shot-2017-01-04-at-10-27-00-am

Final app.js file

Unfortunately, something was still off when I clicked my links in the browser. The first link was working fine, but the second wasn’t doing anything. Well, technically it was changing the url in the browser, but nothing was going on in my terminal behind the scenes or changing on the web page. The main url is on the left and second link/url on the right.

Something funky was going on with the second link. There were a few characters that were being added – ‘#%2’ – before ‘second’. When I went directly to the ‘/second’ url, everything was cool – my page loaded up correctly. So what was the deal with the extra characters? What’s up Angular?!? I tried changing my href in index.html to include the bang before the ‘/second’. screen-shot-2017-01-04-at-10-55-15-am

And it worked! YAY! I still didn’t know what the heck was going on, but it worked! I thought that Angular, by default, adds a hash to url’s, which is why I included them in the first place. I didn’t know about the bang though. It’s called a hashbang, by the way. There are ways to beautify url’s in Angular, but I’ll leave that to more seasoned Angularites. I hope this will help someone out there! May your journey be smooth and remember – everyone stumbles! Just get back up and keep trekking#!