Skip to main content

Mobomo webinars-now on demand! | learn more.

javascript
Coding JS is an art. As we continue in our JS Fundamentals series we’ll unlock layer by layer the basics to working confidently in the land of Javascript.

Mastering the concept of “scope” is an important step towards mastering writing efficient, easily maintained JavaScript. In this installation of the JS Fundamentals series, we’ll take a high-level look at how JavaScript’s scope works.

There are two levels of scope - “global” and “block.” Of the two, the easiest to explain is global. Global scope variables and functions can be accessed by any portion of the environment in which it’s been created. Examples of this are the window Object or the setTimeout Function in the browser, and Node.js’s require Function.

“Block” scope is a little more tricky - a block scope gets created when you write a Function or a try/catch statement. Unlike other C-based languages, blocks that are defined by braces ({ and }) do not create a new scope; at least, not until ECMAScript 6 is adopted.

Let’s look at a few practical examples.

var foo = “Global variable”;  function globalFunc() {   var bar = “Scoped variable”;    function scopedFunc() {     console.log(‘foo is: ‘ + foo);     console.log(‘bar is: ‘ + bar);   };   scopedFunc(); } globalFunc(); scopedFunc(); 

If you run this, the output that you’ll receive from the two function calls would be “foo is: Global variable”, “bar is: scoped variable”, and a ReferenceError because scopedFunc doesn’t exist in the global scope.

This enables us to write functions (and store variables) that are only relevant to the execution of that scope, which is useful for when you’re running repeated tasks that only need to happen when a specific function is being called, but you don’t necessarily need it to be available anywhere else. Additionally, leveraging scope in this way means that any large variables (if you’re doing some intense data processing like manipulating the points of a GeoJSON map, for example) they can be picked up by the garbage collector when the function’s task is complete, and not continue to sit in memory.

Since we have access to global variables inside of a scope, those variables can get reassigned. Take this example:

var reassignable = ‘I am in the global scope’;  function reassigner() {   reassignable = ‘I am in the block scope’; }   console.log(reassignable); // >> “I am in the global scope”  reassigner(); console.log(reassignable); // >> “I am in the block scope” 

This will return the string “I am in the block scope” in the JavaScript console. Of course, the caveat to this is that you need to be careful with naming your variables. If you reuse a global variable, you’ll overwrite it.

Why is this important?

Scope is crucial to understand when working in JavaScript. The examples we’ve seen so far have been simplistic. One of the most challenging aspects of JavaScript for new developers - the this keyword - is heavily impacted by the scope in which it is being called.

However, it’s bigger than just keeping your this keyword context straight (and that particular subject will be focused on in an upcoming post).

If you’re working on a project of any substantial size (more than some basic prototyping, or a very simple static site with a bit of JavaScript thrown in for some enhancements), chances are good that you’re working with external libraries like jQuery or Modernizr (or, perhaps, both). How do you keep these libraries from colliding with one another? If you have both jQuery and Underscore, for example, how do you ensure that their various each methods don’t get overwritten by the other library?

Technically, these libraries use what’s known as “namespacing,” which is the practice of applying a scope to the library that prevents that library’s methods and variables from overriding the methods and variables of the environment to which they’ve been added.

jQuery uses two - one as an alias of the other - names: jQuery and the more familiar $. Underscore, as you might expect, uses the _ character. Therefore the respective each methods would be $.each and _.each. This is possible through what we’ve been discussing with scoping.

If you look at the code for either library, you’ll see that both are wrapped in something that looks like this:

(function (args…) { })() 

This is what’s known as a closure (and, more specifically, an “Immediately Invoked Function Expression” or IIFE). Though we won’t dig in to closures right now, what we know from what’s been covered so far is that any variables defined within a function is constrained to that function. Therefore, the authors of Underscore can implement their each method inside of that closure and not have to worry about whether or not what they write will interfere with a similarly named function that other libraries may introduce.

Finally, it’s important to note that scope and context aren’t the same thing. Context is all about the specific situation where something is being run, and is most easily explored through the use of the this keyword. Scope is what helps define context.

Variables

As we covered already, variables defined in a scope belong to the scope in which they’re defined. If a new scope is defined within the parent scope, they’ll be accessible the same way that global variables are accessible inside of block scopes.

There’s a caveat to this: if you forget to include the var keyword, any variable you create in a scope is automatically added to the global scope:

var globalVar = 1;  function someFunc() {   var scopeVar = 2;   otherVar = globalVar + scopeVar; }  someFunc();  console.log(‘globalVar: ‘ + globalVar); // >> 1 console.log(‘otherVar: ‘ + otherVar); // >> 3 console.log(‘scopeVar: ‘ + scopeVar); // >> ReferenceError: scopeVar is not defined 

Wait, what was that try/catch thing you mentioned earlier?

The one other place that creates scope, at least in ECMAScript 5, is the try/catch block. This is typically used when you know that a portion of your program has potential to throw an error and you want to make sure that it’s properly handled. The catch portion of this is essentially a function that accepts one argument - the error Object - and it allows you to work with that:

try {   undefFunc(); } catch (err) {   console.log('Error:');   console.log(err);   console.log('--------------------'); }  console.log('Error:'); console.log(err); 

This will print out:

“Error:” [object Error] { ... } // depending on your logging environment, this will either be an object you can interact with or just an indication that an object was logged “--------------------" “Error:” ReferenceError: err is not defined 

Note that the err variable isn’t available in the global scope, while it is available in the catch block’s scope.

In Conclusion

Scope is an important concept to grasp when working with JavaScript (really, with any programming language). As Kyle Simpson points out in his You Don’t Know JavaScript: Scopes & Closures, it’s important to remember that JavaScript is actually not a dynamic language - it’s compiled. When a browser loads a JavaScript file, it offloads the contents of that file to its JavaScript engine, where it’s read, compiled, and executed. Because of this process, it’s important to understand how scopes function, Otherwise you’ll likely run in to unexpected behaviors and errors, especially once your application grows in complexity.

A few good resources (in addition to Kyle Simpson’s book) that help with understanding JavaScript Scope are:

Categories
Author

Web App

This article originally appeared on the Divshot blog. Divshot is a developer-focused platform for deploying modern front-end applications. It was also started with Intridea's support by Michael Bleigh!

A few months ago I came across "Rails' Degenerate Front-End Support" taking Rails to task for slipping behind the state of the art when it comes to front-end dependency management. The pain is real, but the problem isn't that Rails does a bad job with front-end dependencies. The problem is that the front-end has no business living in a Rails app at all.

Web applications in 2005 were engines of request and response. You were always interacting with a snapshot of the data, never the data itself. In this era, it made perfect sense for the server to generate the HTML that landed in the browser. After all, browsers were terrible! IE7 had just come out, Firefox had only a tiny sliver of the market, and anything you could do to keep things server-side was a win.

Sure, AJAX existed and could be cajoled into helping out here and there. By and large, however, the server was running the show. What a difference a decade makes.

What has happened since 2005 came about so gradually that many haven't even realized it happened. Browsers got better. Not just a little better. Browsers got magnificently, insanely, unbelievably better. They became faster, they supported more standards and newer standards, they landed on whole new device categories without giving up (too much) ground. Even better, they started releasing much more frequently ensuring they would continue to get better. In the past decade, the browser has evolved from a document viewer that could be hacked into a basic application provider to a full-blown operating system in its own right.

Backbone, Mind Blown

It all started with Backbone, first of the mainstream modern JavaScript frameworks. Like Rails before it and with just around 1,000 lines of code, it had the audacity to challenge the whole way we built applications. Sure, I'd wired up some pretty complex jQuery code by 2010, even dabbled with real-time, but Backbone was the first library that shouted in your face "your front-end is an application." It showed us a map that showed just how far we had come since 2005, and gave us a glimpse of what was to come.

The seed of the idea had been planted. Your front-end is an application. It makes perfect sense and has now for some time. We test the limits. We move from pull to push. We build more and better interaction away from the request/response mindset. And our users love it. The web is more alive today than it's ever been.

So where does that leave Rails?

We're Gonna Need a Bigger Toolbox

Rails has an inherently monolithic mindset. It's a web app in a box. It's a fantastic framework for tying application code to a data store and preparing that data for rendering to the browser. It has thousands of libraries written by thousands of developers to do thousands of things extremely well. You can still build a great modern web application using Rails. You just can't build one only using Rails.

Yes, Rails has the asset pipeline. There are gems that let you use Bower, Angular, Ember, and everything else you might imagine inside your Rails app. But front-ends aren't kids anymore, and it's starting to get embarrassing when they're still living in their parents' basement.

By now, most Rails developers have picked one or more of the modern JS frameworks to use when building apps. Whether it's Backbone, Angular, Ember, or something else. It's not a change in tools that's needed, it's a change in perspective.

The back-end is for persisting and retrieving data. The front-end is for user interaction. And the two should not live in the same repo anymore.

A Modern Approach

I still love Ruby. JavaScript runs in the browser and has better conventions around concurrency, but if I have a choice of language I'm still picking Ruby. But today when I start building a new application, I make two folders: myapp-api and myapp-web.

In my front-end app, I use a variety of tools suited to the purpose like Yeoman, Broccoli, Grunt, or even just bare HTML. In my back-end app, I create a JSON interface to my application logic and data stores using Grape or Sinatra. I deploy the two applications to two separate servers: api.myapp.com for the back-end, and myapp.com or www.myapp.com for the front-end.

The result is a change both much smaller and much bigger than you'd expect. Before I had completely cut the cord between front and back-end, I was already effectively building two separate applications. I just had the artificial constraint that they needed to live in the same repository for some reason.

After the separation, I find that my architecture is much cleaner. I can focus on a single purpose. When I'm working on the back-end, I worry only about a clear and logical representation of application data. When I'm working on the front-end, my only concern is user experience. More than that, it feels right. It feels like I'm building things correctly.

I'm not saying Rails is dead. While I've moved on to lighter frameworks (admittedly, one I designed myself), Rails is still an extremely capable way to implement your web app's back-end. I just think we should stop pretending that there can or should be a single framework that encompasses all the needs of a modern web application.

Keeping front-end and back-end tightly coupled is condemning them to run a three-legged race, awkwardly tied together when both would benefit from separation. Cut the tie. You'll be glad you did.


Categories
Author

 

angular-ruby-on-rails-logo
In Part 2 of Angular with Rails series, we covered creating a Rails API with tests in RSpec and setting up an AngularJS app that reads from the API.

In Part 3 we will cover:

  • Adding CSS
  • Adding editing functionality
  • Creating a custom filter
  • Setting up JavaScript tests

Setup Bootstrap Sass

In order to support editing functionality we'll add some CSS to the UI. Following the README at bootstrap-sass, we'll add to our Gemfile:

gem 'bootstrap-sass', '~> 3.3.0' 

Add to our app/assets/javascripts/application.js:

//= require bootstrap-sprockets 

Rename app/assets/stylesheets/application.css to application.css.sass (if you prefer sass over scss) and add:

@import "bootstrap-sprockets" @import "bootstrap" 

Then we'll add some classes to our employee index in app/views/employees/index.html.erb:

<div ng-app='app.employeeApp' ng-controller='EmployeeListCtrl' class="col-xs-8">   <h1>Employees List</h1>   <table ng-if="employees" class="table table-hover table-striped">     <thead>       <th>Name</th>       <th>Email</th>       <th>SSN</th>       <th>Salary</th>     </thead>     <tbody>       <tr ng-repeat="employee in employees">         <td>{{employee.name}}</td>         <td>{{employee.email}}</td>         <td>{{employee.ssn}}</td>         <td>{{employee.salary | currency}}</td>       </tr>     </tbody>   </table> </div> 

Add the Edit API

Next, we'll update our Rails API to support editing of employee records. Let's start by adding some tests for the update method in spec/controllers/api/employees_controller_spec.rb:

require 'spec_helper'  describe Api::EmployeesController do   before(:each) do     @employee = create(:employee, name: 'Calhoun Tubbs', salary: 50000)   end    describe '#index' do     it 'should return a json array of users' do       get :index       result = JSON.parse(response.body)        expect(result[0]['name']).to eq('Calhoun Tubbs')     end   end    describe "#update" do     it 'should successfully respond to edits' do       put :update, id: @employee.id, employee: {             id: @employee.id,             salary: 60000           }        expect(response).to be_success     end      it "should change the employee's salary" do       @employee.update_attribute(:salary, 50000)        put :update, id: @employee.id, employee: {             id: @employee.id,             salary: 60000           }        expect(@employee.reload.salary).to eq(60000)     end   end end 

At this point, these tests will fail. We need to create an update method in our API controller, but first we must specify what params are allowed on update (Rails' strong parameters) at app/controllers/api/employees_controller.rb:

class Api::EmployeesController < ApplicationController # section omitted   private    def employee_params     attributes = [       :salary,       :name,       :email,       :ssn     ]      params.require(:employee).permit(attributes)   end end 

Now, our update action is simple. The code will try to update the employee object and render the errors if there's a problem.

class Api::EmployeesController < ApplicationController   # section omitted   def update     employee = Employee.find(params[:id])      if employee.update(employee_params)       render json: employee     else       render json: employee.errors.messages, status: :bad_request     end   end   # section omitted end 

Next run the tests to make sure they pass. For a more complex application there would be more tests, but in our example these will suffice.

Add the Edit Front End

For our employee edit functionality we'll define a modal dialog containing a form and a submit button. The Angular-bootstrap package contains a modal dialog tool. We'll add the angular-bootstrap package to our bower.json:

{   "lib": {     "name": "bower-rails generated lib assets",     "dependencies": {       "angular": "v1.2.25",       "restangular": "v1.4.0",       "angular-bootstrap": "v0.11.0"     }   },   "vendor": {     "name": "bower-rails generated vendor assets",     "dependencies": {     }   } } 

And bundle exec rake bower:install

Next, require angular-bootstrap in app/assets/javascripts/application.js:

//= require jquery //= require jquery_ujs //= require angular //= require angular-rails-templates //= require lodash //= require restangular  //= require angular-bootstrap //= require bootstrap-sprockets  //= require angular-app/app // rest of the file omitted 

Finally, we'll add it as a dependency to our angular app in app/assets/javascripts/angular-app/modules/employee.js.coffee.erb:

@employeeApp = angular   .module('app.employeeApp', [     'restangular',     'ui.bootstrap'     'templates'   ])   .run(->     console.log 'employeeApp running'   ) 

Now, we need to add a modal controller to our AngularJS app. This controller will handle popping up a modal editable form and submitting it to our Rails API. In app/assets/javascripts/angular-app/controllers/employee/EmployeeListCtrl.js.coffee:

angular.module('app.employeeApp').controller("EmployeeListCtrl", [   '$scope', 'EmployeeService', '$modal',   ($scope, EmployeeService, $modal)->      $scope.editEmployee = (employee) ->       modalInstance = $modal.open({         templateUrl: 'employee/edit.html',         controller: 'EmployeeEditModalCtrl'         size: 'lg'         resolve:           employee: ->             employee       })        modalInstance.result.then(->         console.log 'edit closed'       ) # rest of file omitted 

Next, we'll create the modal controller at app/assets/javascripts/angular-app/controllers/employee/EmployeeEditModalCtrl.js.coffee:

angular.module('app.employeeApp').controller('EmployeeEditModalCtrl', [   '$scope', '$modalInstance', 'employee', ($scope, $modalInstance, employee)->     $scope.submitEmployee = ->       console.log 'submit employee'      $scope.cancel = ->       $modalInstance.dismiss('cancel')  ]) 

In the above code we're defining a modal controller that receives the employee object we passed in the prior controller, along with function stubs for the save / cancel buttons in the dialog. Next, we need to define the edit form template in app/assets/javascripts/angular-app/templates/employee/edit.html.erb:

<div class="modal-header">   <h4 class="modal-title">Edit Employee</h4> </div>  <div class="modal-body">   <form name="" ng-submit="submitEmployee(employee)">     <div class="form-group">       <div class="row">         <div class="col-xs-12">           <label>Name<span class="required"> required</span></label>           <input class="form-control" ng-model="employee.name">         </div>       </div>     </div>      <div class="form-group">       <div class="row">         <div class="col-xs-12">           <label>Email<span class="required"> required</span></label>           <input class="form-control" ng-model="employee.email">         </div>       </div>     </div>      <div class="form-group">       <div class="row">         <div class="col-xs-12">           <label>SSN<span class="required"> required</span></label>           <input class="form-control" ng-model="employee.ssn">         </div>       </div>     </div>      <div class="form-group">       <div class="row">         <div class="col-xs-12">           <label>Salary<span class="required"> required</span></label>           <input class="form-control" ng-model="employee.salary">         </div>       </div>     </div>      <div class="modal-footer">       <button type="button" class="btn btn-default" data-dismiss="modal" ng-click="cancel()">Cancel</button>       <button type="submit" class="btn btn-primary">Save Changes</button>     </div>   </form> </div> 

Finally, if you run the code now you'll get an error loading the template. We need to tell our angular-rails-templates gem what the base path for our templates is. This is necessary because we are using the rails asset pipeline to combine our javascript files. In config/application.rb:

require File.expand_path('../boot', __FILE__) require 'rails/all'  Bundler.require(*Rails.groups)  module AngularExample   class Application < Rails::Application     # the path relative to app/assets/javascripts     config.angular_templates.ignore_prefix  = 'angular-app/templates/'   end end 

Next, we can return to our employees index and provide an ng-click attribute to launch the edit form. We'll add this link on the employee name cell in the table in app/views/employees/index.html.erb:

# rest of the file omitted <td><a ng-click="editEmployee(employee)">{{employee.name}}</a></td> 

Now, clicking an employee's name will launch a modal form with fields containing that employee's data. However, we still need to hook up the Save Changes button to our Rails API. In app/assets/javascripts/angular-app/controllers/employee/EmployeeEditModalCtrl.js.coffee:

angular.module('app.employeeApp').controller('EmployeeEditModalCtrl', [   '$scope', '$modalInstance', 'employee', ($scope, $modalInstance, employee)->     $scope.employee = employee      $scope.submitEmployee = (employee)->       employee.put().then(         $modalInstance.close('saved')       )     # section omitted ]) 

We can simply say put() above because we are using Restangular to manage that object.

One problem with the above code is that while the server is applying validation to the object, the client side AngularJS portion is not. One downside of using client-side MVC is the fact that validation from the server must often be duplicated on the client. The subject of AngularJS form validation could be a blog post on its own. I'll leave that as an exercise for the reader.

Secure the UI

Though the editing functionality now works, notice the page still shows each employee's social security number. In order to mask the SSN and only reveal it in edit form, we can create an AngularJS filter. In app/assets/javascripts/angular-app/filters/employee/empMaskNumber.js.coffee

angular.module('app.employeeApp').filter('empMaskNumber', ()->   (value, nonMaskLength) ->     if value?       maskLength = value.length - nonMaskLength - 1       if maskLength > 0         v = value.split("")         for i in [0..maskLength] by 1           if v[i] != '-'             v[i] = '*'         v = v.join('')       else         value     else       value ) 

It's recommended that you name filters with an app prefix to avoid colliding with AngularJS's built-in filters. Let's edit our employee table to make use of the filter in app/views/employees/index.html.erb:

# section omitted <tr ng-repeat="employee in employees">   <td><a ng-click="editEmployee(employee)">{{employee.name}}</a></td>   <td>{{employee.email}}</td>   <td>{{employee.ssn | empMaskNumber: 4 }}</td>   <td>{{employee.salary | currency}}</td> </tr> # section omitted 

Viewing the employee table again you should see the SSN field being masked with asterisks except the last 4 digits. While this filter is simple and apparently works, when building more complex filters we will need javascript tests.

Setup JavaScript Tests

Next, we'll setup jasmine-rails. Add jasmine-rails to the Gemfile:

group :test, :development do   gem 'jasmine-rails' end 

And add angular-mocks to the bower.json:

{   "lib": {     "name": "bower-rails generated lib assets",     "dependencies": {       "angular": "v1.2.25",       "restangular": "v1.4.0",       "angular-bootstrap": "v0.11.0",       "angular-mocks": "v1.3.2"     }   },   "vendor": {     "name": "bower-rails generated vendor assets",     "dependencies": {     }   } } 

Then run:

bundle install rails generate jasmine_rails:install bundle exec rake bower:install 

Next, we need to setup our spec_helper. In app/assets/javascripts/spec_helper.coffee:

#= require application #= require angular-mocks #= require sinon  beforeEach(module('app', 'app.employeeApp'))  beforeEach inject (_$httpBackend_, _$compile_, $rootScope, $controller, $location, $injector, $timeout, $filter) ->   @scope = $rootScope.$new()   @compile = _$compile_   @location = $location   @controller = $controller   @injector = $injector   @http = @injector.get('$httpBackend')   @timeout = $timeout   @model = (name) =>     @injector.get(name)   @filter = $filter   @eventLoop =     flush: =>       @scope.$digest()  afterEach ->   @http.resetExpectations()   @http.verifyNoOutstandingExpectation() 

Note the beforeEach line above. As your application grows and more angular apps are added, they must also be added here to be available for testing. The above spec helper also requires SinonJS. Download the file and place it at vendor/assets/javascripts/sinon.js .

Now you should be able to run an empty test suite:

RAILS_ENV=test bundle exec rake spec:javascript 

Which should return 0 specs and 0 failures. We are now ready to write our test for our filter defined above. In spec/javascripts/filters/emp_mask_number_spec.js.coffee:

#= require spec_helper  describe 'Filters', ->   describe 'EmpMaskNumber', ->     beforeEach ->       @maskFilter = @filter('empMaskNumber')      it 'should mask the value with asterisks', ->       @value = "123"       @nonMaskLength = 0        expect(@maskFilter(@value, @nonMaskLength)).toEqual "***" 

In a real application expect to have more specs than just the above. At this point though, you have everything you need to continue building your application and expanding. You can find the code for this example on Github.

Need to catch up on the Angular with Rails series? Check these out:

  • Angular with Rails Part I
  • Angular with Rails, Part II

Resources:

Categories
Author

Jobs
So you're applying for your first job, or you've been around the block and are looking to join a new, exciting team. Congratulations on this new chapter in your professional life!

Applying for a job is a little bit like selling a car. Make sure what you're selling is presentable, that the paperwork is in order, and that your advertising brings potential buyers through the door. I've been through the interviewing process (on both sides) for UX/UI designers, Ruby on Rails, and as of late, Angular developers and have quickly picked up on what works (and what doesn't). Below are a few helpful tips as you navigate the job application journey...

Cover Letter

Don’t skip this one. Call me old fashioned, but the cover letter is the first impression you will make. It doesn’t have to be long or very detailed. Include something you saw or heard about the company to which you are applying. Quick example- “I have seen your open source contribution on GitHub and I would love to work for a place that supports open source.” I think of the cover letter as stepping into your in-laws' house for the first time. Would you walk in, and without saying a word, sit down on the couch? Probably not. Unfortunately, a lot of people don’t send cover letters. Don’t be one of them.

Your Work

There is a saying, "You are as good as your last project”. Make sure your latest and best work is easily seen. Provide working URLs, or links to GitHub repos, and a little bit of information about your role. If you don’t have active apps or websites to check out, provide screenshots or code examples instead. If you are fresh out of school or your current job did not lead to a portfolio, design or build something on your own that you can show. Applying for a job without work examples immediately puts you at a disadvantage, no matter how good your resume is. Invest some time into presenting your latest work. This is your opportunity to show your skill and passion. It will pay off for many years to come.

Resume

Simple is smart. Keep your resume in a simple and easy-to-read layout. Most likely, your resume will be read on a screen and not on paper. Keep that in mind when you select fonts and font sizes. Don’t go overboard and design a resume that looks like a brochure for a Disney cruise. Have your resume available in Word and PDF format. PDF will look nicer because you can use custom fonts. Some large businesses want you to submit an editable word doc, not a PDF. At Intridea, we are happy to accept your nicely formatted PDF resume. Thank you :)

  • Include your full contact info and include your LinkedIn URL if you have an account.
  • Give your resume a file name that is useful, for example: FullName-Resume.pdf
  • Attach a page with a list of your latest work.

Don’t create a long list of every programming language and server technology under the sun. It is not impressive. Instead, it shows a lack of focus and raises the question, "What is she/he really good at?" Good example: If you are applying for a Ruby on Rails developer position, make sure your Ruby on Rails experience is listed first and highlighted. If you have experience in other programming languages and frameworks, list them in a separate paragraph.

Meetings & Communications

Most likely, your first meeting will happen over the phone. Make sure you are in a quiet place and your voice is coming through loud and clear. Calling from Starbucks while you are waiting for your Grande Mocha won’t be impressive. In the days of Skype and GoToMeeting, don’t be afraid to hop on a web meeting with video. When you receive emails, reply promptly with simple language. Don’t reply with novels. When you are invited for a face to face meeting, dress appropriately. Better to be overdressed then under dressed.

Salary

Now to the big question. What to say when your new employer is asking you about your future salary? Don’t stay quiet. If you do, mostly likely the employer will offer a salary that is under market value. Do your homework. Research the position you are after and find out what a fair salary is based on your location and experience. With a little bit of intel, you will feel more confident asking for your future salary and it shows your new employer you know your industry.

Good luck and if you are looking for a new position as Angular, Ruby on Rails developer, or UX/UI designer apply here: http://jobs.intridea.com/

Categories
Author

This article originally appeared on the Divshot blog. Divshot is a developer-focused platform for deploying modern front-end applications. It was also started with Intridea's support by Michael Bleigh!
Web Components are a collection of standards that allow folks to bundle markup and styles into custom HTML elements. They enable truly encapsulated and reusable components for the web and we just can't get enough of 'em at Divshot.

Thus, we'd like to share a little with you! Below are two screen-casts from our monthly Web Components Meetups. Enjoy.

Web Components, a Crash Course

We believe that web components are the future of web development. It's the front-end execution of compartmentalizing app architecture components.

In this video, I'll walk you through what web components are, how to use them, and why they matter, all in under 40 minutes.

Styling Web Components w/ Polymer

The beauty of Polymer components is how easy it is to style them and shipped as a single drop-in element. Jake Johnson walks you through the Shadow DOM and the included powerful tools for building a clean UI.

Got any questions, ideas, thoughts? Let us know!

Categories
Author

This article originally appeared on the Divshot blog. Divshot is a developer-focused platform for deploying modern front-end applications. It was also started with Intridea's support by Michael Bleigh!

If you're diving into Polymer and the new world of Web Components, you may be wondering how to organize and structure your project. We don't have all the answers, but here's what we've found so far.

The structure of an application can be just as important for developer productivity as the frameworks and technologies upon which it's built. When something entirely new (like Polymer) comes along, it can take some time to settle into best practices. At Divshot we've been building small apps and a few larger ones using Polymer for the past year or so. This post summarizes what we've learned thus far about structuring apps.

Note: This isn't an introduction to Polymer but an exploration of best practices for those already using it. Try the official tutorial for a proper intro.

The Basic Structure

When we start building a Polymer app, we don't start with a complex generator toolchain. In fact, we don't start with a build process at all. It can make sense to add one in later depending on how large and complex your app gets, but Web Components are browser-native and it's nice to be able to take advantage of that!

The directory structure of our Polymer apps start something like this:

public/   bower_components/   components/   index.html .gitignore bower.json divshot.json README.md 

Pretty self-explanatory. The divshot.json is there for hosting on Divshot (of course), but also to use its custom routing to make index.html work for any URL during local development in true Single-Page App fashion.

Our .gitignore simply makes sure that we aren't checking in the contents of our Bower install:

/public/bower_components 

Bower is Your Friend

If you want to be productive, you absolutely need Bower. It's how the Polymer team is managing their own code, and you won't want to fight it.

So make sure you run bower init and create a .bowerrc file in your project's directory that points to the proper place. For many of our projects, the .bowerrc looks like:

{"directory":"public/bower_components"} 

If you plan to use Polymer UI Elements or Paper Elements, each comes with a "Kitchen Sink" package that installs all of its elements. While useful during development, you're unlikely to use every single one of them. There's a trick to make this easier: install the aggregate packages locally for development, but only add to bower.json the specific ones that you're using. So start with:

bower install Polymer/paper-elements bower install PolymerLabs/polymer-ui-elements 

And the first time you use one of the components (e.g. paper-ui-button) in your app, install it to your bower.json:

bower install --save Polymer/paper-ui-button 

Naming Elements

We've found it to be a helpful practice to come up with a short prefix that you apply to all of your application specific elements. This might just be app, but probably works better with your actual application name. For example, Polymer's Topeka example app prefixes its elements with topeka-.

Managing Element Dependencies

The public/components directory is where you'll be placing all of the custom elements that you build. In the beginning, this will likely be a simple list of .html files named after the elements, potentially with .css files to go along with them. A typical file will look like:

 <link rel="import" href="../bower_components/some-element/some-element.html"> <link rel="import" href="app-another-element.html">  <polymer-element name="app-my-element">   <template>     <link rel="stylesheet" href="app-my-element.css">        </template>   <script>     Polymer('app-my-element', {       // ...     });   </script> </polymer-element> 

Your dependencies will either come from inside the components directory or from your bower_components. It's your call whether to use absolute (e.g. /bower_components/some-element/some-element.html) or relative (e.g. ../bower_components/some-element/some-element.html) paths. Each has advantages and drawbacks, and we haven't settled on a clearly superior option yet.

You should always import all required dependencies at the top of an element. Even if you are using the same element in many files, you should have an import link at the top of each one. This way if you move things around, you won't accidentally break dependencies.

The only exception we've carved out to this rule is polymer.html which we directly import in the index.html file just after platform.js since every element we build requires it.

Alternative: Separate Elements Repository

Again referencing the Polymer teams' Topeka app, they to created a separate topeka-elements repository for all of their app's custom elements. While we can only speculate, it's likely that they did this so that they could install all the elements with Bower and consistently use relative path imports (e.g. ../some-element/some-element.html) in their code.

There are definitely advantages to this method, and it's one we're evaluating to see if it feels superior or more productive. The greatest challenge is in the need to constantly commit to two repositories that are tightly coupled as your application grows and changes.

Building Reusable Elements

Web Components are composable and reusable like nothing that has come before. In the course of making your app, you're likely to come up with a few elements that could easily be used for other purposes. The Polymer team has a great guide on creating reusable elements that we highly recommend, but it can be tough to work on one in the context of a larger app. Here's how we do it:

  1. Follow the linked guide above, but put the project folder for your new element inside public/bower_components.
  2. Initialize it as a separate git repository. Since its parent folder is ignored by git, you won't have a conflict in doing this.
  3. Publish your new element to GitHub. You don't have to register it with Bower just yet.
  4. Manually add a dependency to your bower.json for your new reusable component.

So long as you remember to push your changes up from your reusable component, your colleagues will be able to install it alongside all their other Bower dependencies.

Bundling Elements

One of the biggest "a ha!" moments we had while planning out structure was how to manage groups of related components. The answer was to utilize one of the web's oldest features: the directory index file!

As you begin to group elements together (maybe by feature, by function, whatever makes sense to you) you can create subdirectories in your public/components directory to house them. Then just create an index.html file that imports all of the grouped components. For example:

 <link rel="import" href="blog-post.html"> <link rel="import" href="blog-category.html"> <link rel="import" href="blog-comments.html"> 

Now when you want to be able to use these related elements, you can do so with a single import:

<link rel="import" href="components/blog/"> 

It's when you do things like this that you understand just how wonderfully well-designed the Web Components architecture is, and how well it fits into the existing HTML world.

Concatenation and Build Process

Most of our apps are still in the development phase and not quite ready for public consumption. As such, we don't have deep experience with trying to optimize Polymer apps for speed or network performance (yet).

Vulcanize is going to be a good place to start looking, though.


These are some of the tips and tricks that we've learned so far. Are you building Polymer apps? If so, what have you learned to be as productive as possible? Let us know!

Categories
Author

Angular

In Part I of our Angular series, we illustrated the process for setting up an Angular app for Rails.

In Part 2 of this series, we'll be creating a basic HR app. This app will allow us to view employee information through an Angular app (edits and updates to be explained in Part 3 of this series). For more details, see code in Github link at the end of post.

Here's a quick snapshot of what we'll be creating for our HR app:

  • Setting up test frameworks
  • Creating a Rails API
  • Making the Angular frontend talk to the Rails API

Setup RSpec

First, remove the test/ directory. This is left over from our initial app setup in Part 1: How to Set Up Angular with Rails. Then add RSpec and factory_girl_rails to the Gemfile:

group :development, :test do   gem 'rspec-rails', '~> 3.1.0' end  group :test do   gem 'database_cleaner'   gem 'factory_girl_rails' end 

Next, bundle and install it.

bundle install rails generate rspec:install 

And edit your spec/spec_helper.rb to match:

ENV["RAILS_ENV"] ||= 'test' require File.expand_path("../../config/environment", __FILE__) require 'rspec/rails' require 'rspec/autorun' require 'database_cleaner'  ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration) RSpec.configure do |config|   config.include FactoryGirl::Syntax::Methods   config.infer_spec_type_from_file_location!    config.expect_with :rspec do |expectations|     expectations.include_chain_clauses_in_custom_matcher_descriptions = true   end    config.mock_with :rspec do |mocks|     mocks.verify_partial_doubles = true   end end 

Create the Employee Model

Let's create the Employee model with a few fields:

bundle exec rails generate model Employee name:string email:string ssn:string salary:integer bundle exec rake db:migrate 

Next, we'll add some validations in app/models/employee.rb:

class Employee < ActiveRecord::Base   # regex taken from Devise gem   validates_format_of :email, with: /A[^@s]+@([^@s]+.)+[^@s]+z/   validates_format_of :ssn, with: /d{3}-d{2}-d{4}/   validates_presence_of :name   validates :salary, numericality: { only_integer: true } end 

Before creating the API interface for Angular, let's create a serializer for our Employee model. This will allow our API to expose only those fields that are necessary to Angular frontend. Add ActiveModel Serializers to the Gemfile

gem 'active_model_serializers' 

And bundle install

Create the Employee API

In order to support the Angular frontend, we'll need to create an API controller at app/controllers/api/employees_controller.rb:

class Api::EmployeesController < ApplicationController   respond_to :json    def index     serialized_employees =       ActiveModel::ArraySerializer                .new(Employee.all, each_serializer: EmployeeSerializer)      render json: serialized_employees   end end 

Now we need to define that EmployeeSerializer in app/serializers/employee_serializer.rb:

class EmployeeSerializer < ActiveModel::Serializer   attributes :id, :name, :email, :ssn, :salary end 

And expose this API to the frontend in config/routes.rb:

Rails.application.routes.draw do   get 'example' => 'example#index'    namespace :api do     resources :employees, defaults: { format: :json }   end end 

Finally we'll add some Employee data to db/seeds.rb:

Employee.create(name: "MacGyver", email: "test@example.com", ssn: "555-55-5555", salary: 50000) Employee.create(name: "Calhoun Tubbs", email: "test2@example.com", ssn: "123-45-6789", salary: 60000) 

Seed the database and start the Rails server:

bundle exec rake db:seed rails s 

Then we can open http://localhost:3000/api/employees in the browser which will return:

[   {     "id": 1,     "name": "MacGyver",     "email": "test@example.com",     "ssn": "555-55-5555",     "salary": 50000   },   {     "id": 2,     "name": "Calhoun Tubbs",     "email": "test2@example.com",     "ssn": "123-45-6789",     "salary": 60000   } ] 

Test the API

Now that we've verified this action is set-up correctly, let's add a factory at spec/factories/employees.rb:

FactoryGirl.define do   factory :employee do     name 'Test Employee'     email 'test@example.com'     salary 50000     ssn '123-45-6789'   end end 

Next, add a test at spec/controllers/api/employees_controller_spec.rb:

require 'spec_helper'  describe Api::EmployeesController do   before(:each) do     create(:employee, name: 'Calhoun Tubbs')   end    describe '#index' do     it 'should return a json array of users' do       get :index       result = JSON.parse(response.body)        expect(result[0]['name']).to eq('Calhoun Tubbs')     end   end end 

While the above test is somewhat trivial, this set up is great for verifying more complex logic in real world applications. In addition, the reason for adding an API spec prior to the Angular portion is to avoid playing the guessing game if/when problems arise; waiting to add the Angular framework helps to ease the deciphering process. If your Angular app isn't working correctly, its important to verify that the Rails backend is also behaving correctly -- the problem may not be an Angular issue.

Create the Angular frontend

You may want to take a look back at Part 1: How to Set Up Angular with Rails to review how we setup the AngularJS frontend with Rails. Let's start by defining an app in app/assets/javascripts/angular-app/modules/employee.js.coffee.erb:

@employeeApp = angular   .module('app.employeeApp', [     'restangular'   ])   .run(->     console.log 'employeeApp running'   ) 

Next, we'll define the Employees controller in app/controllers/employees.rb:

bundle exec rails g controller Employees index 

Then, we'll add to the beginning of config/routes.rb:

root 'employees#index' 

Finally, let's start the Angular app in app/views/employees/index.html.erb:

<div ng-app='app.employeeApp' ng-controller='EmployeeListCtrl'> </div> 

If you run the Rails server and hit http://localhost:3000/ you'll get an error about the controller not being defined yet in the javascript console. Before we create the controller, let's setup a Employee model and service to handle fetching Employee records from the Rails API.

The Employee model is defined at app/assets/javascripts/angular-app/models/employee/Employee.js.coffee:

angular.module('app.employeeApp').factory('Employee',[() ->   Employee = () ->    return new Employee() ]) 

There is no special behavior here yet. It is only returning the data that comes from the API.

To ease the process of working with APIs in Angular, let's add the restangular library to our project. In bower.json add restangular:

  "lib": {     "name": "bower-rails generated lib assets",     "dependencies": {       "angular": "v1.2.25",       "restangular": "v1.4.0"     }   }, 

Then run bundle exec rake bower:install. Next, we need to add restangular and its dependency lodash to app/assets/javascripts/application.js:

//= require jquery //= require jquery_ujs //= require angular //= require angular-rails-templates //= require lodash //= require restangular 

Afterwards, we'll create the Employee service at app/assets/javascripts/angular-app/services/employee/EmployeeService.js.coffee:

angular.module('app.employeeApp')   .factory('EmployeeService', [     'Restangular', 'Employee',     (Restangular, Employee)->        model = 'employees'        Restangular.extendModel(model, (obj)->         angular.extend(obj, Employee)       )        list: ()     -> Restangular.all(model).getList()   ]) 

Finally, let's create the controller at app/assets/javascripts/angular-app/controllers/employee/EmployeeListCtrl.js.coffee:

angular.module('app.employeeApp').controller("EmployeeListCtrl", [   '$scope', 'EmployeeService',   ($scope, EmployeeService)->      EmployeeService.list().then((employees) ->       $scope.employees = employees       console.dir employees     ) ]) 

If you run the Rails server and visit http://localhost:3000/ in the javascript console you'll see a print out of the Employee objects previously seeded to the database. Next, let's add to the template code to show our Employee objects. In app/views/employees/index.html.erb:

<div ng-app='app.employeeApp' ng-controller='EmployeeListCtrl'>   <table ng-if="employees">     <thead>       <th>Name</th>       <th>Email</th>       <th>SSN</th>       <th>Salary</th>     </thead>     <tbody>       <tr ng-repeat="employee in employees">         <td>{{employee.name}}</td>         <td>{{employee.email}}</td>         <td>{{employee.ssn}}</td>         <td>{{employee.salary | currency}}</td>       </tr>     </tbody>   </table> </div> 

Open http://localhost:3000 and notice the salary field. We used the currency filter to handle formatting that data. Salary comes back from the API as a plain integer value. Angular has a number of useful filters that are included by default.

The above example is very basic. However, we created database objects, exposed those via an API, tested the API, and created an Angular app to handle the frontend. That's no small task! A few pieces are still missing though. While our Ruby API has tests, our Angular app has no tests at all. Furthermore, our employee management app is view-only.

Github code for HR app here.

In Part 3, we'll setup javascript tests, and add editing functionality to our Angular frontend. In the meantime, review Part 1 and if you have any questions feel free to message us on Twitter.

Categories
Author

This article originally appeared on the Divshot blog. Divshot is a developer-focused platform for deploying modern front-end applications. It was also started with Intridea's support by Michael Bleigh!
Motion is quickly becoming one of the most important emerging techniques in building a quality user experience on the web. Angular 1.2, currently in release candidate form, provides an overhaul of Angular's animation system and makes it spectacularly easy to bring your interface to life.

Of course, hand keying animations can be time consuming especially when you're trying to prototype something in quick order. Luckily, Animate.css provides a library of ready-to-go animations that can be dropped in quickly and easily. But how can we use these together?

Introduction to Angular 1.2 Animations

Animations in Angular 1.2 take a very simple convention-based approach. Here's basically how it works:

  1. Angular automatically detects and triggers animations based on certain events (namely enter, leave, and move)
  2. When one of those events occur, Angular automatically attaches a special class to the element (for example ng-enter when a new item is added to a list, for example)
  3. This class can be used for setup (for example, to set attributes for the "before" of a transition), but after this class is applied another class is applied (ng-enter-active, for example) to indicate that the animation should begin.
  4. The ng-{event} and ng-{event}-active classes are removed automatically after the animation concludes (determined by introspecting the CSS and determining transition duration)

This all sounds relatively complex, but it's actually quite simple in practice. Basically, for a custom animation you would just need to define some CSS like so (vendor prefixes omitted for brevity):

.some-element.ng-enter {   transition: height 1s;   height: 0px;   overflow: hidden; }  .some-element.ng-enter-active {   height: 100px; } 

The above code would automatically resize an element from zero height to 100px over the course of 1 second when the "enter" event is triggered.

Animating on CSS Class Changes

In addition to events like enter and leave, Angular provides the ability to attach animations to the addition and removal of any class. One of the most common ways would be for show/hide. If I have:

<div class="fader" ng-hide="checked">Animate this!</div> 

This works basically the same as if I had this:

<div class="fader" ng-class="{'ng-hide': hidden}">Animate this!</div> 

To trigger animations when classes are added and removed, you just apply transitions or animations to the class name with -add and -remove postfixes. Here's an example of how I might make a fading animation for ng-hide:

.fader.ng-hide-add {   opacity: 1.0;   display: block !important;   transition: opacity 1s; }  .fader.ng-hide-add-active {   opacity: 0; } 

Activating Angular 1.2 Animations

To use animations in your Angular code, you will need to include the separate angular-animate.js file. If you're using Google's CDN, you can include both Angular 1.2 and Angular Animation in your code. You will also need to create an angular module that consumes the ngAnimate provider to activate animations:

<html ng-app="myApp">   <head>          <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.2/angular.min.js"></script>     <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.2/angular-animate.min.js"></script>     <script>       var app = angular.module('myApp', ['ngAnimate']);     </script>   </head>   <body>        </body> </html> 

One of the most powerful aspects of Angular 1.2 animation is that you don't have to specifically invoke it; instead, it "just works" when any animation-triggering event happens in your page.

Bringing in Animate.css

But what about that nice library of existing animation we already have with animate.css? Simple: because Animate.css provides named keyframe animations, you simply need to apply the given animation to the element when the appropriate Angular animation class is applied. Here's a simple fade in/fade out scenario:

.my-element.ng-enter {   animation: fadeIn 1s; }  .my-element.ng-leave {   animation: fadeOut 1s; } 

That's seriously all there is to it! You can use any of the named animations from Animate.css in the same manner and it will all work, fast and easy.

To demonstrate how easily this can be accomplished, I used Divshot to quickly snap together a "todo list" interface and added some animations. I've published the result to JS Bin, just click below to see the code.

View Todo List Demo
Got any questions, suggestions, ideas? Keep the conversation going! We'd love to hear from you.

Categories
Author

dear maggie

The benefits of remote working are tremendous; from flexible schedules and commuter free work days to working in your pajamas! At Intridea, we are huge proponents of this lifestyle and have written loads of articles on working effectively, and communicating efficiently in it. However, there's one topic that's gone unnoticed, the relational side of remote working. As a five year veteran, Maggie has experienced many of the relational pitfalls remote working can come with and has heard the same from many of her peers. Thus, she and Intridea have decided to do something about it...

Introducing - “Dear Maggie” - a resource for remote workers who may be facing the friction that can often surface when your home becomes your full time office.

Send your burning questions over to dearmaggie@intridea.com, and we’ll address them!


Dear Maggie,

I recently started working for a company that’s fully distributed (remote). The adjustment has been great and I’m really enjoying my new work situation, there’s only one problem.

My wife works a traditional 9-5 job and is consistently annoyed when she returns home to find I haven’t done any housework. I don’t think this is fair, as she isn’t expected to clean during her work-day, and I’m busy doing my own job during the day.

How can I help her to understand I need to put in 8 hours of work too and can’t do all the cleaning while she’s away?

Annoyed in Annapolis


Hey Annoyed,

One of the hardest parts to adjusting to remote working is negotiating a new normal with your partner. Many times people new to remote working are careful to define expectations for themselves, and for their new employer, but not their significant other. I think we’re both in agreement that your wife’s expectations are unfair; both of you work during the day, yours just happens to be from home while hers is at an office.

However, keep in mind, it may be that your wife is questioning your time at home, because she doesn’t see you clean enough when she is around. Perhaps this is an opportunity to address the split of household duties, and put together an amenable plan.

Here are a few tips to ensure success:

  1. Indicate you’re interested in finding a plan that ensures no one (especially her) feels like they’re doing more than their ½ of the work. This way you’re approaching the conversation from a place of positivity rather than complaining.
  2. Own the goal of coming up with a plan and come prepared! Start a chart to help track duties, or a list of the tasks you’ve identified to keep the conversation productive. After you get it nailed down, post it somewhere where it’s easily accessible by both of you.
  3. Setting your partner’s expectations about what she’ll see you do is only half the battle, be sure to discuss the details of when you prefer to accomplish your ½ of the duties too. This way she doesn’t expect the laundry to be done on Tuesdays when you’d prefer to do it on Sunday mornings. Talking it through beforehand ensures no one is let down.
  4. Stick to it. Whatever you two agree on, you have to hold up your end of the bargain. Setting expectations only helps if you meet those expectations.

Every relationship is different, and I wouldn’t say there’s one “silver bullet” for this problem. Nevertheless setting expectations is always a great start. Working remote adds new variables to a relationship - but it doesn’t have to be overwhelming! Being intentional in both your work and family life can be as simple as a list, conversation, or schedule - just take the time and address these issues head on...

Enjoy this post? Check out the rest of our DISTRIBUTED articles here!

Categories
Author

When it comes to Angular and Rails, there are many ways to set up a project. However when starting out, all these options can be a tad overwhelming…

Over the last few months, I’ve been focusing on project set-ups and have come to find a few favorites. In this post, I'll illustrate one way to use Rails with Angular (see Github links with the example code below).

Create a New Rails App

To get started lets create a new rails app.

gem install rails -v 4.1 rails new angular_example 

In this app, I chose not to use turbolinks. It's possible to use Angular with Rails and turbolinks, but the Angular app bootstrap process is more complex. I find that turbolinks and Angular serve the same purpose, which is to make the app respond faster. Adding turbolinks, in addition to Angular, adds a lot of complexity and not much benefit.

Remove Turbolinks

Removing turbolinks requires removing it from the Gemfile.

gem 'turbolinks' 

Remove the require from app/assets/javascripts/application.js

//= require turbolinks 

Add AngularJS to the Asset Pipeline

In order to get Angular to work with the Rails asset pipeline we need to add to the Gemfile:

gem 'angular-rails-templates' gem 'bower-rails' 

Next, we can install these gems into our bundle.

bundle install 

We added bower so that we can install the AngularJS dependency.

rails g bower_rails:initialize json 

When adding Angular to bower.json, I prefer to specify the most recent version rather than going with the "latest". This avoids having your app randomly break when a new version is released and your bower installs again.

{   "lib": {     "name": "bower-rails generated lib assets",     "dependencies": {       "angular": "v1.2.25"     }   },   "vendor": {     "name": "bower-rails generated vendor assets",     "dependencies": {     }   } } 

Now that bower.json is setup with the right dependencies, let's install them:

bundle exec rake bower:install 

Organize the Angular App

At this point we'll create the following folder structure in app/assets/javascript/angular-app:

templates/ modules/ filters/ directives/ models/ services/ controllers/ 

This structure is only a convention and is not enforced by Angular (unlike file naming and organization in Rails). This project structure allows for a single web app to be easily composed of multiple smaller Angular modules rather than one giant Angular app for the whole site.

In app/assets/javascripts/application.js add Angular, the template helper, and the Angular app file structure. That file should now read like this:

//= require jquery //= require jquery_ujs //= require angular //= require angular-rails-templates  //= require angular-app/app //= require_tree ./angular-app/templates //= require_tree ./angular-app/modules //= require_tree ./angular-app/filters //= require_tree ./angular-app/directives //= require_tree ./angular-app/models //= require_tree ./angular-app/services //= require_tree ./angular-app/controllers 

Bootstrap the Angular App

Next, we'll setup the Angular app bootstrapping. Create app/assets/javascripts/angular-app/app.js.coffee:

@app = angular.module('app', [   # additional dependencies here, such as restangular   'templates' ])  # for compatibility with Rails CSRF protection  @app.config([   '$httpProvider', ($httpProvider)->     $httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content') ])  @app.run(->   console.log 'angular app running' )  

Then, we'll create an Angular module at app/assets/javascripts/angular-app/modules/example.js.coffee.erb

@exampleApp = angular   .module('app.exampleApp', [     # additional dependencies here   ])   .run(->     console.log 'exampleApp running'   ) 

Following the Angular module, we'll create an Angular controller for this app at app/assets/javascripts/angular-app/controllers/exampleCtrl.js.coffee

angular.module('app.exampleApp').controller("ExampleCtrl", [   '$scope',   ($scope)->     console.log 'ExampleCtrl running'      $scope.exampleValue = "Hello angular and rails"  ]) 

Now we need to add a route to Rails to pass control over to Angular. In config/routes.rb:

Rails.application.routes.draw do   get 'example' => 'example#index' end 

Next, we'll generate the Rails controller to respond to that route:

rails g controller Example 

In app/controllers/example_controller.rb:

class ExampleController < ApplicationController   def index   end end 

In the view we need to specify which Angular app, and which Angular controller will drive this page.

In app/views/example/index.html.erb:

<div ng-app='app.exampleApp' ng-controller='ExampleCtrl'>   <p>Value from ExampleCtrl:</p>   <p>{{ exampleValue }}</p> </div> 

To view the app, start your Rails server and visit http://localhost:3000/example

You can find the code generated here https://github.com/rawsyntax/rails-angular-example

Categories
Author
Subscribe to