angular.js + rails at wework or: the accidental feature

34
Angular.js + Rails = or: The Accidental Feature By Sr. Software Engineer, Jonathan E. Magen / @yonkeltron WeWork

Upload: jonathan-magen

Post on 05-Dec-2014

4.164 views

Category:

Technology


1 download

DESCRIPTION

for 2013-03-19 Angular.js NYC Meetup

TRANSCRIPT

Page 1: Angular.js + Rails at WeWork or: The Accidental Feature

Angular.js + Rails = ♥or: The Accidental Feature

By Sr. Software Engineer, Jonathan E. Magen / @yonkeltron WeWork

Page 2: Angular.js + Rails at WeWork or: The Accidental Feature

Identify yourselfJonathan E. Magen / errywhere elsePractitioner of the Computer SciencesResearch @ Advanced OS LabWeWork engineer

yonkeltron

The Evergreen State College

Page 3: Angular.js + Rails at WeWork or: The Accidental Feature

About WeWork

- Adam Neumann, WeWork Co-Founder

- Miguel McKelvey, WeWork Co-Founder

7 Buildings3 Cities4000+ MembersServices for the community

“ We want to change the way people work. ”

“ Design to make people happy. ”

Page 5: Angular.js + Rails at WeWork or: The Accidental Feature

WeWork.com MemberNetwork

Page 6: Angular.js + Rails at WeWork or: The Accidental Feature
Page 7: Angular.js + Rails at WeWork or: The Accidental Feature

Spaceman: WeWorkbackoffice hawtness

Space managementBillingReservationsAccounting system integration

Page 8: Angular.js + Rails at WeWork or: The Accidental Feature

Things we've built withAngular

Audit trail + changelog inspector using gemInfinite scroll using gemInline editLots of stuff using

auditedwill_paginate

ngResource

Page 9: Angular.js + Rails at WeWork or: The Accidental Feature

Angular.js + Rails♥

Page 10: Angular.js + Rails at WeWork or: The Accidental Feature

Free RESTful JSON endpoints

ActiveRecord → JSON → HTTP

class OfferingsController < ApplicationController

def index @offerings = Offering.page(params[:page])

respond_to do |format| format.html # index.html.erb format.json { render json: @offerings, root: false } end end

# other actions...end

Page 11: Angular.js + Rails at WeWork or: The Accidental Feature

ngResource

Rails → JSON/HTTP → ngResource

angular.module('offeringsService', ['ngResource']). factory('Offering', function offering($resource) { return $resource('/offerings/:id', {id: '@id'}, { create: { method: 'POST' }, index: { method: 'GET', isArray: true }, show: { method: 'GET' }, update: { method: 'PUT' } }); });

Page 12: Angular.js + Rails at WeWork or: The Accidental Feature

Rails renders Angular template HTMLTimes you might want to do this:

Permissions: only rendering parts of a templateDynamically populate form select optionsInternationalization!

Page 13: Angular.js + Rails at WeWork or: The Accidental Feature

Permission-driven rendering

Only render the audit inspector directive iff the current user has theauthorization to access audit data

<%= if current_user.has_role? :auditor %> <div data-ng-app="spaceman"> <div data-audits="yep" data-auditable-type="<%= Offering.to_s %>" data-auditable-id="<%= @offering.id %>"></div> </div><% end %>

Page 14: Angular.js + Rails at WeWork or: The Accidental Feature

i18n API column headers

thead rendered by Rails includes localized column headers. Thislets Angular render the tbody containing actual data.

<table class="table table-striped" data-ng-app="spaceman"> <thead> <th><%= Offering.human_attribute_name(:name) %></th> <th><%= Offering.human_attribute_name(:categorization) %></th> <th><%= Offering.human_attribute_name(:price) %></th> <th></th> <th></th> </thead>

Page 15: Angular.js + Rails at WeWork or: The Accidental Feature

One minor snag

config/environments/production.rb

config.assets.js_compressor = Sprockets::LazyCompressor.new do Uglifier.new(mangle: false) # don't obliterate namesend

Page 16: Angular.js + Rails at WeWork or: The Accidental Feature

Angular on RailsRails gives you RESTful JSON endpoints for free

lets you consume them for freeLet Rails help you render templatesngResource

Page 17: Angular.js + Rails at WeWork or: The Accidental Feature

The Accidental Feature

Page 18: Angular.js + Rails at WeWork or: The Accidental Feature

It started with a spikeThe requirement:

Allow a user to quickly inline edit inventory on the index page.

*Actual Spaceman wireframe

Page 19: Angular.js + Rails at WeWork or: The Accidental Feature

The search forinline edit

Oh God, please make it stop

Page 20: Angular.js + Rails at WeWork or: The Accidental Feature

Yeah, I know there were easierways to do thisGorillions of jQuery pluginsFar fewer Angular-friendly options

We knew we'd need Angular.js butwanted to ease our way in gradually

Google GroupsStackOverflow

Page 21: Angular.js + Rails at WeWork or: The Accidental Feature

A subtle rejection of Reimplementing table in terms of divDoes way more than what we neededSub project of

TBH: Angular.js could really use widgets

ngGrid

Angular UI

Web Components?

Page 22: Angular.js + Rails at WeWork or: The Accidental Feature

How we did it

Page 23: Angular.js + Rails at WeWork or: The Accidental Feature

Offerings controller

spaceman.controller('offerings', function ($scope, searchParamService, Offering) { console.log('Offerings Contoller');

$scope.offerings = Offering.query(); // ngResource ZOMG!

$scope.editingToggle = function editingToggle(offering) { if (offering.editing) { Offering.update(offering); offering.editing = false; } else { offering.editing = true; } };});

Page 24: Angular.js + Rails at WeWork or: The Accidental Feature

The show/hide model for cellsin the table body

show(value) ⊕ show(input)

<tbody data-ng-controller="offerings"> <tr data-ng-repeat="offering in offerings"> <td> <a href="/offerings/{{offering.id}}" data-ng-show="!offering.editing">{{offering.name}}</a>

<input data-ng-show="offering.editing" type="text" data-ng-model="offering.name" required/> </td>

Page 26: Angular.js + Rails at WeWork or: The Accidental Feature

ProblemsVerboseSoaking wet (non-DRY)Not easily reused

Page 27: Angular.js + Rails at WeWork or: The Accidental Feature

Next steps for inline editFigure out how to turn this in to a reusable component

Page 28: Angular.js + Rails at WeWork or: The Accidental Feature

Accidental success↓

Angular empowerment

Page 29: Angular.js + Rails at WeWork or: The Accidental Feature

Changelog + audit inspectorStrong audit trailData integrity

gemaudited

Page 30: Angular.js + Rails at WeWork or: The Accidental Feature

Who, what, when, where, why, how

class Offering < ActiveRecord::Base audited

# ...end

Audited::Adapters::ActiveRecord::Audit < ActiveRecord::Base { :id => :integer, :auditable_id => :integer, :auditable_type => :string, :associated_id => :integer, :associated_type => :string, :user_id => :integer, :user_type => :string, :username => :string, :action => :string, :audited_changes => :text, # <- ZOMG diff :version => :integer, :comment => :string, :remote_address => :string, :created_at => :datetime}

Page 31: Angular.js + Rails at WeWork or: The Accidental Feature
Page 32: Angular.js + Rails at WeWork or: The Accidental Feature
Page 33: Angular.js + Rails at WeWork or: The Accidental Feature
Page 34: Angular.js + Rails at WeWork or: The Accidental Feature

END / FIN / סוף

Thanks to GoogleThanks to WeWork

Thanks to you