diff --git a/Changelog.md b/Changelog.md
index 409acf0b7a2d3e60e44ca4db36dd8c6733bfdb45..a531e0b94510f2791c0628a2c54526ad91ce1f73 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -34,6 +34,7 @@
 * Added link to diasporafoundation.org to invitation email [#5893](https://github.com/diaspora/diaspora/pull/5893)
 * Gracefully handle missing `og:url`s [#5926](https://github.com/diaspora/diaspora/pull/5926)
 * Remove private post content from "also commented" mails [#5931](https://github.com/diaspora/diaspora/pull/5931)
+* Add a button to follow/unfollow tags to the mobile interface [#5941](https://github.com/diaspora/diaspora/pull/5941)
 
 # 0.5.0.1
 
diff --git a/app/assets/javascripts/app/helpers/handlebars-helpers.js b/app/assets/javascripts/app/helpers/handlebars-helpers.js
index c428bfdd74cb0a9797dcea2166e1883bc3c0cdd3..1862dc11bece2071398a4d2f73ad7e9467913dd7 100644
--- a/app/assets/javascripts/app/helpers/handlebars-helpers.js
+++ b/app/assets/javascripts/app/helpers/handlebars-helpers.js
@@ -12,13 +12,13 @@ Handlebars.registerHelper('imageUrl', function(path){
   return ImagePaths.get(path);
 });
 
-Handlebars.registerHelper('urlTo', function(path_helper, id, data){
+Handlebars.registerHelper("urlTo", function(pathHelper, id, data){
   if( !data ) {
     // only one argument given to helper, mangle parameters
     data = id;
-    return Routes[path_helper+'_path'](data.hash);
+    return Routes[pathHelper](data.hash);
   }
-  return Routes[path_helper+'_path'](id, data.hash);
+  return Routes[pathHelper](id, data.hash);
 });
 
 Handlebars.registerHelper('linkToAuthor', function(context, block) {
@@ -89,32 +89,32 @@ Handlebars.registerHelper('localTime', function(timestamp) {
   return new Date(timestamp).toLocaleString();
 });
 
-Handlebars.registerHelper('fmtTags', function(tags) {
+Handlebars.registerHelper("fmtTags", function(tags) {
   var links = _.map(tags, function(tag) {
-    return '<a class="tag" href="' + Routes.tag_path(tag) + '">' +
-           '  #' + tag +
-           '</a>';
-  }).join(' ');
+    return "<a class=\"tag\" href=\"" + Routes.tag(tag) + "\">" +
+           "  #" + tag +
+           "</a>";
+  }).join(" ");
   return new Handlebars.SafeString(links);
 });
 
-Handlebars.registerHelper('fmtText', function(text) {
+Handlebars.registerHelper("fmtText", function(text) {
   return new Handlebars.SafeString(app.helpers.textFormatter(text));
 });
 
-Handlebars.registerHelper('isCurrentPage', function(path_helper, id, options){
+Handlebars.registerHelper("isCurrentPage", function(pathHelper, id, options){
   var currentPage = "/"+Backbone.history.fragment;
-  if (currentPage === Handlebars.helpers.urlTo(path_helper, id, options.data)) {
+  if (currentPage === Handlebars.helpers.urlTo(pathHelper, id, options.data)) {
     return options.fn(this);
   } else {
     return options.inverse(this);
   }
 });
 
-Handlebars.registerHelper('isCurrentProfilePage', function(id, diaspora_handle, options){
-  var username = diaspora_handle.split("@")[0];
-  return Handlebars.helpers.isCurrentPage('person', id, options) ||
-         Handlebars.helpers.isCurrentPage('user_profile', username, options);
+Handlebars.registerHelper("isCurrentProfilePage", function(id, diasporaHandle, options){
+  var username = diasporaHandle.split("@")[0];
+  return Handlebars.helpers.isCurrentPage("person", id, options) ||
+         Handlebars.helpers.isCurrentPage("userProfile", username, options);
 });
 
 Handlebars.registerHelper('aspectMembershipIndicator', function(contact,in_aspect) {
diff --git a/app/assets/javascripts/app/models/person.js b/app/assets/javascripts/app/models/person.js
index 0cfcc9f669765eaaac74eab00c8bdd49c7458317..8c9a7241a04174b381f3d99955bc8fcd9e5ba39d 100644
--- a/app/assets/javascripts/app/models/person.js
+++ b/app/assets/javascripts/app/models/person.js
@@ -2,7 +2,7 @@
 
 app.models.Person = Backbone.Model.extend({
   url: function() {
-    return Routes.person_path(this.get('guid'));
+    return Routes.person(this.get("guid"));
   },
 
   initialize: function() {
diff --git a/app/assets/javascripts/app/pages/contacts.js b/app/assets/javascripts/app/pages/contacts.js
index 27e7ec1268e8519913e6df12ba2dbbc754eaaf5f..782120b22ff6554b69c185f411e22ac41333bca1 100644
--- a/app/assets/javascripts/app/pages/contacts.js
+++ b/app/assets/javascripts/app/pages/contacts.js
@@ -83,7 +83,7 @@ app.pages.Contacts = Backbone.View.extend({
       update: function() {
         $("#aspect_nav .ui-sortable").removeClass("synced");
         var data = JSON.stringify({ ordered_aspect_ids: $(this).sortable("toArray", { attribute: "data-aspect-id" }) });
-        $.ajax(Routes.order_aspects_path(),
+        $.ajax(Routes.orderAspects(),
           { type: "put", dataType: "text", contentType: "application/json", data: data })
           .done(function() { $("#aspect_nav .ui-sortable").addClass("synced"); });
       },
diff --git a/app/assets/javascripts/app/pages/profile.js b/app/assets/javascripts/app/pages/profile.js
index 767c9f3a22837038b9b073a1a2afd73cc39d12d9..f9f24da73b3ebfba9bfaf040d194b43cff0cf1f9 100644
--- a/app/assets/javascripts/app/pages/profile.js
+++ b/app/assets/javascripts/app/pages/profile.js
@@ -76,11 +76,11 @@ app.pages.Profile = app.views.Base.extend({
     }
 
     // a collection is set, this means we want to view photos
-    var route = this.streamCollection ? 'person_photos_path' : 'person_stream_path';
+    var route = this.streamCollection ? "personPhotos" : "personStream";
     var view = this.streamViewClass ? this.streamViewClass : app.views.Stream;
 
     app.stream = new app.models.Stream(null, {
-      basePath: Routes[route](app.page.model.get('guid')),
+      basePath: Routes[route](app.page.model.get("guid")),
       collection: this.streamCollection
     });
     app.stream.fetch();
diff --git a/app/assets/javascripts/app/views/help_view.js b/app/assets/javascripts/app/views/help_view.js
index 6cbcdf25c6125ad58e44029ac984edbcf164b928..f1ec4618f7a437ba0b17b202fc31860bfd939110 100644
--- a/app/assets/javascripts/app/views/help_view.js
+++ b/app/assets/javascripts/app/views/help_view.js
@@ -40,7 +40,7 @@ app.views.Help = app.views.StaticContentView.extend({
     this.CHAT_SUBS = {
       add_contact_roster_a: {
         toggle_privilege: this.getChatIcons(),
-        contacts_page: this.linkHtml(Routes.contacts_path(), Diaspora.I18n.t('chat.contacts_page'))
+        contacts_page: this.linkHtml(Routes.contacts(), Diaspora.I18n.t("chat.contacts_page"))
       }
     };
 
diff --git a/app/assets/javascripts/app/views/notification_dropdown_view.js b/app/assets/javascripts/app/views/notification_dropdown_view.js
index a2c7525db3a859ab4d1211c9a477b8ea96515e5a..36de9c954b95c5a9723181f48bb3685184d2741d 100644
--- a/app/assets/javascripts/app/views/notification_dropdown_view.js
+++ b/app/assets/javascripts/app/views/notification_dropdown_view.js
@@ -74,7 +74,7 @@ app.views.NotificationDropdown = app.views.Base.extend({
 
   getNotifications: function(){
     var self = this;
-    $.getJSON(Routes.notifications_path(this.getParams()), function(notifications){
+    $.getJSON(Routes.notifications(this.getParams()), function(notifications){
       $.each(notifications, function(){ self.notifications.push(this); });
       self.hasMoreNotifs = notifications.length >= self.perPage;
       if(self.nextPage){ self.nextPage++; }
diff --git a/app/assets/javascripts/app/views/single-post-viewer/single_post_moderation.js b/app/assets/javascripts/app/views/single-post-viewer/single_post_moderation.js
index ad636addf1a5a9159f54cf0cb6e3f5801c454bf7..8604d1adc91141cc518294bd61736a8fa1a53556 100644
--- a/app/assets/javascripts/app/views/single-post-viewer/single_post_moderation.js
+++ b/app/assets/javascripts/app/views/single-post-viewer/single_post_moderation.js
@@ -49,7 +49,7 @@ app.views.SinglePostModeration = app.views.Feedback.extend({
   createParticipation: function (evt) {
     if(evt) { evt.preventDefault(); }
     var self = this;
-    $.post(Routes.post_participation_path(this.model.get("id")), {}, function () {
+    $.post(Routes.postParticipation(this.model.get("id")), {}, function () {
       self.model.set({participation: true});
       self.render();
     });
@@ -58,7 +58,7 @@ app.views.SinglePostModeration = app.views.Feedback.extend({
   destroyParticipation: function (evt) {
     if(evt) { evt.preventDefault(); }
     var self = this;
-    $.post(Routes.post_participation_path(this.model.get("id")), { _method: "delete" }, function () {
+    $.post(Routes.postParticipation(this.model.get("id")), { _method: "delete" }, function () {
       self.model.set({participation: false});
       self.render();
     });
diff --git a/app/assets/javascripts/app/views/stream_post_views.js b/app/assets/javascripts/app/views/stream_post_views.js
index fb44250f64b700910f5489c685a87268d45a8608..60a965136901d4a690935d5be84e40718403ec4e 100644
--- a/app/assets/javascripts/app/views/stream_post_views.js
+++ b/app/assets/javascripts/app/views/stream_post_views.js
@@ -119,7 +119,7 @@ app.views.StreamPost = app.views.Post.extend({
   createParticipation: function (evt) {
     if(evt) { evt.preventDefault(); }
     that = this;
-    $.post(Routes.post_participation_path(this.model.get("id")), {}, function () {
+    $.post(Routes.postParticipation(this.model.get("id")), {}, function () {
       that.model.set({participation: true});
       that.render();
     });
@@ -128,7 +128,7 @@ app.views.StreamPost = app.views.Post.extend({
   destroyParticipation: function (evt) {
     if(evt) { evt.preventDefault(); }
     that = this;
-    $.post(Routes.post_participation_path(this.model.get("id")), { _method: "delete" }, function () {
+    $.post(Routes.postParticipation(this.model.get("id")), { _method: "delete" }, function () {
       that.model.set({participation: false});
       that.render();
     });
diff --git a/app/assets/javascripts/mobile/profile_aspects.js b/app/assets/javascripts/mobile/profile_aspects.js
index 11769b4bd26171f8202aedb265959d7feadd8b75..2c664f045ef005fb14fe1a93ed44fea17919749a 100644
--- a/app/assets/javascripts/mobile/profile_aspects.js
+++ b/app/assets/javascripts/mobile/profile_aspects.js
@@ -27,14 +27,14 @@ $(document).ready(function(){
 
     if(selected.hasClass('selected')) {
       // remove from aspect
-      var membership_id = selected.data('membership_id');
+      var membershipId = selected.data("membership_id");
 
       $.ajax({
-        url: Routes.aspect_membership_path(membership_id),
-        type: 'DELETE',
-        dataType: 'json',
+        url: Routes.aspectMembership(membershipId),
+        type: "DELETE",
+        dataType: "json",
         headers: {
-          'Accept': "application/json, text/javascript, */*; q=0.01"
+          "Accept": "application/json, text/javascript, */*; q=0.01"
         }
       }).done(function() {
         selected.text("– " + Diaspora.I18n.t('aspect_dropdown.mobile_row_unchecked', {name: selected.data('name')}));
@@ -50,7 +50,7 @@ $(document).ready(function(){
       var person_id = $el.data('person-id');
 
       $.ajax({
-        url: Routes.aspect_memberships_path(),
+        url: Routes.aspectMemberships(),
         data: JSON.stringify({
           "person_id": person_id,
           "aspect_id": parseInt(selected.val(), 10)
diff --git a/app/assets/javascripts/mobile/tag_following.js b/app/assets/javascripts/mobile/tag_following.js
index ef46ac984dd2dba089b119ce7e962e8e413bfd89..43eda00538b06a9bcd730919d3acc1df49ec6830 100644
--- a/app/assets/javascripts/mobile/tag_following.js
+++ b/app/assets/javascripts/mobile/tag_following.js
@@ -6,7 +6,7 @@ $(document).ready(function(){
 
     if(button.hasClass("btn-success")){
       $.ajax({
-        url: Routes.tag_followings_path(),
+        url: Routes.tagFollowings(),
         data: JSON.stringify({"name": tagName}),
         type: "POST",
         dataType: "json",
@@ -26,7 +26,7 @@ $(document).ready(function(){
       var tagFollowing = _.findWhere(gon.preloads.tagFollowings,{name: tagName});
       if(!tagFollowing) { return; }
       $.ajax({
-        url: Routes.tag_following_path(tagFollowing.id),
+        url: Routes.tagFollowing(tagFollowing.id),
         dataType: "json",
         type: "DELETE",
         headers: {
diff --git a/app/assets/templates/profile_header_tpl.jst.hbs b/app/assets/templates/profile_header_tpl.jst.hbs
index 516ae8345fa130af966d30dbe6bf91d0e0dc226d..45c06f9ebacafadf01db66c36fa8b954852554ae 100644
--- a/app/assets/templates/profile_header_tpl.jst.hbs
+++ b/app/assets/templates/profile_header_tpl.jst.hbs
@@ -2,7 +2,7 @@
   <div class="pull-right">
     {{#if is_own_profile}}
       {{!-- can't block myself, so don't check it here --}}
-      <a href="{{urlTo 'edit_profile'}}" id="edit_profile" class="btn btn-primary creation">{{t 'people.edit_my_profile'}}</a>
+      <a href="{{urlTo 'editProfile'}}" id="edit_profile" class="btn btn-primary creation">{{t 'people.edit_my_profile'}}</a>
     {{else}} {{#if is_blocked}}
       <a href="#" id="unblock_user_button" class="btn btn-danger">{{t 'people.stop_ignoring'}}</a>
     {{else}}
@@ -31,7 +31,7 @@
         <div class="description">
           <i>{{t 'profile.you_have_no_tags'}}</i>
           <span class="add_tags">
-            <a href="{{urlTo 'edit_profile'}}">{{t 'profile.add_some'}}</a>
+            <a href="{{urlTo 'editProfile'}}">{{t 'profile.add_some'}}</a>
           </span>
         </div>
       {{/if}}
@@ -74,8 +74,8 @@
         </a>
       </li>
       {{#if show_photos}}
-        <li {{#isCurrentPage 'person_photos' guid}} class="active" {{/isCurrentPage}}>
-          <a href="{{urlTo 'person_photos' guid}}" id="photos_link">
+        <li {{#isCurrentPage 'personPhotos' guid}} class="active" {{/isCurrentPage}}>
+          <a href="{{urlTo 'personPhotos' guid}}" id="photos_link">
             <i class="entypo picture"></i>
             {{t 'profile.photos'}}
             <div class="badge badge-default">{{photos.count}}</div>
@@ -83,7 +83,7 @@
         </li>
       {{/if}}
       {{#if show_contacts}}
-        <li {{#isCurrentPage 'person_contacts' guid}} class="active" {{/isCurrentPage}}>
+        <li {{#isCurrentPage 'personContacts' guid}} class="active" {{/isCurrentPage}}>
           {{#if is_own_profile}}
             <a href="{{urlTo 'contacts'}}" id="contacts_link">
               <i class="entypo users"></i>
@@ -91,7 +91,7 @@
               <div class="badge badge-default">{{contacts.count}}</div>
             </a>
           {{else}}
-            <a href="{{urlTo 'person_contacts' guid}}" id="contacts_link">
+            <a href="{{urlTo 'personContacts' guid}}" id="contacts_link">
               <i class="entypo users"></i>
               {{t 'profile.contacts'}}
               <div class="badge badge-default">{{contacts.count}}</div>
diff --git a/config/initializers/jsroutes.rb b/config/initializers/jsroutes.rb
new file mode 100644
index 0000000000000000000000000000000000000000..64ee94599b1ef27fb0786e3680e3bd81f8bcba2c
--- /dev/null
+++ b/config/initializers/jsroutes.rb
@@ -0,0 +1,4 @@
+JsRoutes.setup do |config|
+  config.camel_case = true
+  config.compact = true
+end
diff --git a/spec/javascripts/app/models/person_spec.js b/spec/javascripts/app/models/person_spec.js
index b36b8beb685c321ccc20560c8571bd1db81a1010..21f18d658c737cbd8e817208df9f140f962a00c9 100644
--- a/spec/javascripts/app/models/person_spec.js
+++ b/spec/javascripts/app/models/person_spec.js
@@ -1,69 +1,69 @@
 
 describe("app.models.Person", function() {
   beforeEach(function() {
-    this.mutual_contact = factory.person({relationship: 'mutual'});
-    this.sharing_contact = factory.person({relationship :'sharing'});
-    this.receiving_contact = factory.person({relationship: 'receiving'});
-    this.blocked_contact = factory.person({relationship: 'blocked', block: {id: 1}});
+    this.mutualContact = factory.person({relationship: "mutual"});
+    this.sharingContact = factory.person({relationship: "sharing"});
+    this.receivingContact = factory.person({relationship: "receiving"});
+    this.blockedContact = factory.person({relationship: "blocked", block: {id: 1}});
   });
 
   context("#isSharing", function() {
     it("indicates if the person is sharing", function() {
-      expect(this.mutual_contact.isSharing()).toBeTruthy();
-      expect(this.sharing_contact.isSharing()).toBeTruthy();
+      expect(this.mutualContact.isSharing()).toBeTruthy();
+      expect(this.sharingContact.isSharing()).toBeTruthy();
 
-      expect(this.receiving_contact.isSharing()).toBeFalsy();
-      expect(this.blocked_contact.isSharing()).toBeFalsy();
+      expect(this.receivingContact.isSharing()).toBeFalsy();
+      expect(this.blockedContact.isSharing()).toBeFalsy();
     });
   });
 
   context("#isReceiving", function() {
     it("indicates if the person is receiving", function() {
-      expect(this.mutual_contact.isReceiving()).toBeTruthy();
-      expect(this.receiving_contact.isReceiving()).toBeTruthy();
+      expect(this.mutualContact.isReceiving()).toBeTruthy();
+      expect(this.receivingContact.isReceiving()).toBeTruthy();
 
-      expect(this.sharing_contact.isReceiving()).toBeFalsy();
-      expect(this.blocked_contact.isReceiving()).toBeFalsy();
+      expect(this.sharingContact.isReceiving()).toBeFalsy();
+      expect(this.blockedContact.isReceiving()).toBeFalsy();
     });
   });
 
   context("#isMutual", function() {
     it("indicates if we share mutually with the person", function() {
-      expect(this.mutual_contact.isMutual()).toBeTruthy();
+      expect(this.mutualContact.isMutual()).toBeTruthy();
 
-      expect(this.receiving_contact.isMutual()).toBeFalsy();
-      expect(this.sharing_contact.isMutual()).toBeFalsy();
-      expect(this.blocked_contact.isMutual()).toBeFalsy();
+      expect(this.receivingContact.isMutual()).toBeFalsy();
+      expect(this.sharingContact.isMutual()).toBeFalsy();
+      expect(this.blockedContact.isMutual()).toBeFalsy();
     });
   });
 
   context("#isBlocked", function() {
     it("indicates whether we blocked the person", function() {
-      expect(this.blocked_contact.isBlocked()).toBeTruthy();
+      expect(this.blockedContact.isBlocked()).toBeTruthy();
 
-      expect(this.mutual_contact.isBlocked()).toBeFalsy();
-      expect(this.receiving_contact.isBlocked()).toBeFalsy();
-      expect(this.sharing_contact.isBlocked()).toBeFalsy();
+      expect(this.mutualContact.isBlocked()).toBeFalsy();
+      expect(this.receivingContact.isBlocked()).toBeFalsy();
+      expect(this.sharingContact.isBlocked()).toBeFalsy();
     });
   });
 
   context("#block", function() {
     it("POSTs a block to the server", function() {
-      this.sharing_contact.block();
+      this.sharingContact.block();
       var request = jasmine.Ajax.requests.mostRecent();
 
       expect(request.method).toEqual("POST");
-      expect($.parseJSON(request.params).block.person_id).toEqual(this.sharing_contact.id);
+      expect($.parseJSON(request.params).block.person_id).toEqual(this.sharingContact.id);
     });
   });
 
   context("#unblock", function() {
     it("DELETEs a block from the server", function(){
-      this.blocked_contact.unblock();
+      this.blockedContact.unblock();
       var request = jasmine.Ajax.requests.mostRecent();
 
       expect(request.method).toEqual("DELETE");
-      expect(request.url).toEqual(Routes.block_path(this.blocked_contact.get('block').id));
+      expect(request.url).toEqual(Routes.block(this.blockedContact.get("block").id));
     });
   });
 });