How to create a web app that looks like a iOS 7 native app (Part 2: Behavior)

Posted 7 months back at mir.aculo.us - Home

This is part 2 of a 3-part mini-series on designing iOS 7 web apps:

In part 1 of this series you learned some tricks about styling your application—but what about user interaction?

Animation

All the buzz about “reduced” or “flat” styling in iOS 7 is taking the spotlight away from an other major change, more “physical” animations:

People are accustomed to the subtle animation used in the built-in iOS apps. In fact, people tend to regard the smooth transitions between views, the fluid response to changes in device orientation, and the physics-based scrolling as an expected part of the iOS experience. Unless you’re creating an app that enables an immersive experience—such as a game—custom animation should be comparable to the built-in animations. — iOS Human Interface Guidelines

There’s a few important transition animations that come practically for free for native applications, but take a bit of tinkering if you want to recreate these in a web app:

  • “Show panel” animation, when you drill down from a list, or when you show settings
  • “Show modal panel” animation, an animation showing a modal panel scrolling up from the bottom of the screen
  • The controversial physics-simulating rubber-band bouncing scrolling like in the Messages application

panelsAn easy way to analyze animations is to use the iOS Simulator (which comes along Xcode) and a tool to take screen videos. Be sure to export in a lossless format and you’re now able to inspect the animations in detail (I use Final Cut Pro because it makes it easy to step between frames and add markers to get timings, but anything that has a step-by-step frame advance and a timestamp works).

On the left you can see the panel animation when drilling down in a list, which is the same animation I wanted for our mobile web version of Freckle Time Tracking.

Next to the duration of the animation, the easing equation (or in CSS parlance, the “timing function”) is the most important component of an animation. You don’t just move things, you move things with acceleration and deceleration (just like in the real world, here come physics again!). I’ve used Stylie’s Motion tab to design a timing function that’s close to what Apple uses on iOS 7.

If you do a step-by-step analysis of the panel animation, you can see that not only the new panel slides in from the right, but the old panel is sliding 50% to the left while getting less opaque, with a gray background behind it. The text in the navigation bar does some cross-fading as well—it’s actually a quite complex animation.

Caveat: you can only focus form fields as a direct result of a user interaction, like on a click or touchend event. This means that if you want your forms to animate in, you can’t focus a form field via code and users will have to tap the form field they want to edit. This can be fine with editing forms, but with “new” forms you’ll likely want to forego the animation and opt for focusing instead.

Here’s the final animation JavaScript code, using Zepto:

<script src="https://gist.github.com/madrobby/6918742.js"></script>

Home-screen web apps

The final thing that takes a web app closer to being just like a native app is being able to run full-screen, a thing that has been possible for quite a while now on iOS by saving to the home screen. Just like in previous iOS versions, this is possible in iOS 7 as well. Please note that there are several horrendous bugs in the current incarnation of iOS 7 (like no alert() or confirm() modals, mailto: not working and other issues).

Nevertheless, two small tips with this:

Screen Shot 2013-10-10 at 10.02.23 AM
Set the apple-mobile-web-app-status-bar-style meta tag’s content to black-translucent to get a fully translucent phone status bar. You can add a class to your body element to indicate that your application is running from the home screen (if (navigator.standalone) $('#body').addClass('standalone')). When that class is active, add the necessary padding to the top of your page.

Switch to a high resolution (1024×1024) touch icon and rely on apple-touch-icon to provide a correct icon for iOS 6 (with the gloss) and 7. Note that the border radius has changed, I’d suggest to try not to bother to be too clever and let the OS do the job of cutting the icon to the right shape.

Offline?

There’s a hype about designing “offline first”, which I think is a load of crap. These are phones people use, and they’re almost always online, and it will certainly not get worse in the future. I assume an always-on connection, but just in case the connection goes down I show a warning message (that people can easily dismiss, if they choose to).

It’s as easy as…

<script src="https://gist.github.com/madrobby/6919021.js"></script>

…where online and offline are functions that hide or show your offline message.

That’s it for getting your web app closer to iOS 7 behavior—next time I’ll take a look at making cross-device compatible web apps, that load fast, work (almost) everywhere and don’t completely crap out on older devices. Stay tuned!

Please sign up for my newsletter to get this article series (and my other posts) delivered directly into your inbox (plus you’ll get a cool rebate coupon for my ebook “Retinafy your web sites and web apps”!):

Build Phase Podcast Episode 11: Podspec or Bust

Posted 7 months back at GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS - Home

Build Phase Podcast Episode 11: Podspec or Bust:

Gordon Fontenont and Mark Adams speak with Mattt Thompson, Mobile Lead at Heroku, creator of AFNetworking, NSHipster and Helios.

Phusion Passenger 4.0.20 released

Posted 7 months back at Phusion Corporate Blog


Phusion Passenger is a fast and robust web server and application server for Ruby, Python and Node.js. It works by integrating into Apache and Nginx and turning them into a fully-featured application server. It has high-profile users such as New York Times, AirBnB, Juniper, Motorola, etc, and comes with many features that make your life easier and your application perform better.

Phusion Passenger is under constant maintenance and development. Version 4.0.20 is a bugfix release.

Phusion Passenger also has an Enterprise version which comes with a wide array of additional features. By buying Phusion Passenger Enterprise you will directly sponsor the development of the open source version.

Recent changes

  • Fixed a bug in Phusion Passenger Standalone’s daemon mode. When in daemon mode, the Nginx temporary directory was deleted prematurely, causing some POST requests to fail. This was a regression that was introduced in 4.0.15 as part of an optimization.
  • Fixed compilation problems on Solaris 10 with Sun Studio 12.3.
  • Improved detection of RVM problems.
  • It is now possible to log the request method to Union Station.
  • Introduced a new option, `PassengerLoadShellEnvvars` (Apache) and `passenger_load_shell_envvars` (Nginx). This allows enabling or disabling the loading of bashrc before spawning the application.
  • [Enterprise] Fixed a packaging problem which caused the flying-passenger executable not to be properly included in the bin path.
  • [Enterprise] Fixed a race condition which sometimes causes the Flying Passenger socket to be deleted after a restart. Fixes issue #939.
  • [Enterprise] The `byebug` gem is now supported for debugging on Ruby 2.0. The byebug gem requires a patch before this works.

Installing 4.0.20

Quick install/upgrade

Phusion Passenger Enterprise users can download the Enterprise version of 4.0.20 from the Customer Area.

Open source users can install the open source version of 4.0.20 with the following commands. Note that these instructions are very basic and may not cover steps that may be relevant to your specific system, such as setting up the right file permission. Please refer to the in-depth instructions if you have trouble installing.

gem install passenger
passenger-install-apache2-module
passenger-install-nginx-module

You can also download the tarball at the Release Archive page. We strongly encourage you to cryptographically verify files after downloading them.

In-depth instructions

In-depth installation and upgrade instructions can be found in the Installation section of the documentation. The documentation covers.

  • Detailed tarball installation instructions.
  • Detailed upgrade instructions.
  • Installation troubleshooting.
  • Installation through APT and YUM.
  • Installation through OS X Homebrew.

You can view the documentation online here:

Final

Fork us on Github!

Phusion Passenger’s core is open source. Please fork or watch us on Github. :)

<iframe src="http://ghbtns.com/github-btn.html?user=phusion&amp;repo=passenger&amp;type=watch&amp;size=large&amp;count=true" allowtransparency="true" frameborder="0" scrolling="0" width="170" height="30"></iframe><iframe src="http://ghbtns.com/github-btn.html?user=phusion&amp;repo=passenger&amp;type=fork&amp;size=large&amp;count=true" allowtransparency="true" frameborder="0" scrolling="0" width="170" height="30"></iframe><iframe src="http://ghbtns.com/github-btn.html?user=phusion&amp;type=follow&amp;size=large&amp;count=true" allowtransparency="true" frameborder="0" scrolling="0" width="190" height="30"></iframe>

If you would like to stay up to date with Phusion news, please fill in your name and email address below and sign up for our newsletter. We won’t spam you, we promise.



Episode #409 - October 8th, 2013

Posted 7 months back at Ruby5

One day, two rubies with Rubinius 2.0 and JRuby 1.7.5. MRI 2.1 vs Rubinius 2.0 benchmark, Virtus 1.0, Capistrano woes, and help Ruby on Sails.

Listen to this episode on Ruby5

This episode is sponsored by Code School
Spanning 7 levels and bringing you nearly 40 interactive coding challenges, Rails 4 Patterns follows up on Rails Best Practices and teaches you common practices and techniques to help your Rails application stand the test of time. Learn how to avoid pitfalls in ActiveRecord, extract reusable components and concerns, build a JSON API, and more.

Rubinius 2.0
Last Friday, Ruby Hero Brian Shirai announced the release of Rubinius 2.0. And, with this release, Rubinius is moving toward concentrating on being the foundation for modern concurrent and distributed applications.

MRI 2.1 vs. Rubinius 2.0
Miguel Camba put together a blog post where he recorded Ruby benchmarks across MRI, JRuby, and Rubinius using the ruby­benchmark­suite. Rubinius actually ran faster than the current Ruby 2.1 dev branch and even beat JRuby 1.7.4 in all of the multithreaded tests.

JRuby 1.7.5
JRuby 1.7.5 was released yesterday! Aside from a number (243) of issues resolved, this new version brings improved transcoding support, Ripper support, Fiber fixes, and encoding and multilingualization improvements. It seems like pathname, date and time have been sped up. Call performance for magic globals has been increased as well, and block and proc creation and dispatch has been improved as well. It’s interesting to note that as the Rubinius project did, the JRuby project moved several standard library pieces into gems with this release.

Virtus 1.0
This weekend, Piotr Solnica released Virtus 1.0. Virtus was built from extracting the dynamic property definitions in DataMapper into its own library. Think of it kind of similarly to attr_accessor but with 100% more utility, or as they put it, “Attributes on Steroids for Plain Old Ruby Objects.” It supports defaults, type checks, coercion, and a whole lot more. Everyone has probably rolled their own library for doing something like this and Piotr and the rest of the team have done an incredible job with Virtus.

Capistrano woes
Lee Hambley, the maintainer of Capistrano over the last few years posted a heartfelt message to the project’s mailing list last week talking about how we was considering stepping down.

Help Ruby on Sails
A lot of people apparently signed up for Ruby on Sails but sponsors were hard to find and Jim found himself having to put $7,200 of his own money to cover the cost. To help him out you can purchase a Ruby on Sails t­-shirt. If Jim closes the fundraising gap he will donate any excess funds to Rails Girls South Florida. The event is still 4 sponsors short, so don’t hesitate to get in touch with info@rubyonsails.info if you’re interested.

Giant Robots Podcast Episode 69: Geocoding in the Now

Posted 7 months back at GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS - Home

Giant Robots Podcast Episode 69: Geocoding in the Now:

Ben Orenstein interviews Josh Clayton and Laila Winner on their book, Geocoding on Rails.

Announcing the Classical Code Reading Group of Stockholm

Posted 7 months back at GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS - Home

If I were to say that someone is weaving a tangled web, Hell is other people, or if you build it they will come, you would know what I’m trying to express. You know what a catch-22 is. There is a fear of waking up to discover that you are a giant insect, and the phrase “it’s alive!" conjures up not just Frankenstein’s monster but also its poor, misunderstood fate.

So why can I not reference the way the echo program prints a space between each argument, the way GNU false uses C trickery to avoid code duplication, or the classic constant 0x5f3759df without the same recognition?

These are our classics. Not only are these programs we use every day, but they’re written by some of the most influential programmers of generations past, inspiring not just entire operating systems but also design patterns large and small.

The Classical Code Reading Group of Stockholm reads the classics.

In our pilot meetup we examined echo.c across five different implementations. From OpenBSD we learned about minimalism, including this statement that would bring pride to every nihilist:

(void)fputs(*argv, stdout);

NetBSD taught us about dotting our i’s and crossing our t’s, including flushing standard output, watching the return types, and that errors can exist anywhere. From FreeBSD we learned to love again, embracing not the stark minimalism of OpenBSD but instead the industriousness exploration of bare metal input and output.

The GNU echo and its predecessor, the GNU bash echo builtin, showed how to cleanly handle backward compatibility in the face of the complex forward march of progress, including hexadecimal parsing, environment variables, well-named keywords, and short-circuit termination.

This excursion down the guts of echo.c took three hours, with a break for food and drink.

So grab your sense of adventure and join us as we explore true and false, from shell to shining C, and see just how GNU managed to hit 78 lines for this classic, tiny app, at the next Classical Code Reading Group of Stockholm event on the 21st of October.

A Typographic Refactoring

Posted 7 months back at GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS - Home

On Giant Robots, we’ve switched from using Skolar and Proxima Nova via Typekit for our body and header typefaces, to Chronicle Text and Sentinel via the typography.com cloud. We’ve adjusted line-height, weights, vertical rhythm, and the CSS we use to render the type. Typographers sweat every curve and corner when designing a typeface, and as designers we need to take equal care in selecting them. This article explains the intent and technical reasoning behind each adjustment, beginning with the choice of the new typefaces.

Body Text — What Makes Chronicle Text Better?

The first thing to notice is Chronicle Text’s larger size — it’s the main reason the typeface appears more readable, but both faces are set to 16px. Skolar looks smaller because its ascenders and descenders don’t reach the boundaries of its glyph’s bounding box — each glyph in a typeface is contained within a bounding box, the digital descendant of the sort. When type was made in metal, each glyph of the same size was cast into a sort of the same size; Chronicle Text would have just filled more of the sort than Skolar.

Chronicle Text also has a large x-height, the height of its lowercase letters. It’s proportionally taller than Skolar’s x-height, and still clearly differentiated from the uppercase. More height means larger letters and larger counter forms, the enclosed or partially enclosed spaces within a letter. At small sizes, the lines around a counter can blend together due to anti-aliasing and create a fuzzy texture; note the small counter on the letter “e” in “Toomey”.

Skolar is very curvy, you can see how much more consistently vertical and horizontal Chronicle Text’s strokes are in “vim” vs the arched feet of Skolar’s “vim” — the “v” even has an ink trap. This may reproduce well at medium sizes or in print, but on screen at 16px, these details are obscured by pixelated approximations.

Chronicle Text’s lines look closer together due to its larger apparent size, so its line-height needed to be increased. Line-height is somewhat dependent on font weight, x-height, medium, and preference, but a good guideline is to avoid creating a lined texture with too large a line-height, and a dense texture with too little — if the space between lines is smaller than the space between words, it’s definitely too small.

Typography.com allows you to select OpenType features à la carte like kerning pairs and ligatures, but you need to enable text-rendering: optimizeLegibility in your CSS to render these features. There’s a cost to render time relative to the amount of text, but we think it’s worthwhile since our articles are usually short to medium length.

Subheads — Standing Out and Pairing Up

We previously used an all caps Proxima Nova for our subheads. Ellen Lupton (among others) has a rule of thumb to never change more than two things to differentiate a piece of type. The Proxima Nova subhead was larger, bolder, a different case, a separate typeface, and had a different bottom margin than the paragraph text. It’s been replaced by Sentinel Bold, which only changes the typeface and the weight. Sentinel is a beautiful almost-slab-serif from Hoefler & Frere-Jones, and a recommended combination with Chronicle Text. We almost used Chronicle Text Bold for subheads, but decided to go with H&FJ’s recommendation. Sentinel, like slab serifs in general, is built to be bold, so less detail is lost at heavier weights.

Typographic choices are often a matter of taste, and the choice between Sentinel Bold and Chronicle Text Bold is an example. Differences can be small when comparing two typefaces of the same category, and sometimes you have to rely on taste or some other meta information to come to a conclusion. In their rebranding of the Whitney Museum, Experimental Jetset used Neue Haas Grotesk, the product of a collaboration between Swiss and New York type designers, mimicking the collaborations behind the museum’s collection and architecture. In this case, the typeface’s history, not just its appearance, played heavily into the designer’s choice.

Thin Weights and Headlines

H&FJ makes beautiful headline typefaces, but many of them have specific personalities that will end up dominating a page if you’re not careful. We want our headlines to be obvious but unobtrusive, so we chose to keep Proxima Nova at a heavier weight. We didn’t use a light weight anywhere except the headline previously, and it displayed poorly on older and Windows systems. Increasing its weight improves the site’s consistency, scannability, and the reading experience for many of our visitors.

Vertical Rhythm

Vertical rhythm encompasses a lot of ideas on layout, all of which revolve around the vertical spacing of items and type on a page. Print designers work with the finite widths and heights of paper. To avoid overrun, print designers have to use a vertical grid just like most websites use a horizontal one, this ensures that each page ends in the same place, and any two pages on the same system look aligned side-by-side. Since we have no control over our canvas on the web, many of these paradigms no longer make sense. Line heights need to be taller to accommodate longer lines, and the page is arbitrarily cut off in the viewport, vertically and horizontally. The idea of vertical consistency should apply in some places, but not others.

Our sidebar showing tags and the author was previously unaligned with our content; this is easily passed over, but becomes obviously wrong once noticed. In the new design, all the side-by-side pieces are aligned to a vertical grid.

Wrap-up

"I think it’s important for us not to be under the illusion that anybody else cares"
Saul Bass on making beautiful work

Tens (sometimes hundreds) of thousands of people read our blog every month, and although very few of them likely noticed the change, we feel an obligation to create a great reading experience designed with intent down to every detail. If you have a question on anything mentioned, or notice anything unmentioned, tweet @thoughtbot.

Written by Edwin Morris

Episode #408 - October 4th, 2013

Posted 7 months back at Ruby5

Better layouts with Nestive, a Ruby port of the Resty tool, more extensible exception handling with rescue_from, flexible bindings for IRB, compliance with Sandi's rules of Ruby, and Faye 1.0 all in this episode of the Ruby5!

Listen to this episode on Ruby5

This episode is sponsored by New Relic
New Relic is _the_ all-in-one web performance analytics product. It lets you manage and monitor web application performance, from the browser down to the line of code. With Real User Monitoring, New Relic users can see browser response times by geographical location of the user, or by browser type.

Nestive
Want more control over template injection that what `content_for` affords? Take a look at nestive!

Ruby Resty
Now there is a Ruby implementation of the Resty command-line tool!

rescue_from
Rails has a handy but little-known macro called rescue_from. Learn about it in this blog post!

binding.repl
Pry has long held the monopoly on runtime invocation, but now binding.repl allows you to get similar functionality in IRB, Ripl, and Pry.

Sandi-Meter
Sandi Metz' rules have become pretty famous as of late, this tool allows you to visualize your complicance to them.

Faye 1.0
Faye 1.0 was released! Your favorite pub/sub library now with promises!

Chrome for Android gets full-screen web apps

Posted 7 months back at mir.aculo.us - Home

Mobile web apps just got even cooler, with Chrome for Android adding support for full-screen, saved to home screen web apps, making them first-class app citizens like on iOS.

Read about how to implement this on Google’s Developer Docs.

BubbleConf 2013 Recap (Director’s Cut)

Posted 7 months back at Phusion Corporate Blog

BubbleConf is a conference on tech, design and entrepreneurship by Nedap and Phusion. It is targetted towards startups and the 2013 edition was held in the Beurs van Berlage in Amsterdam on September 27th. It had close to 400 people from all over the world attend and we were blown away once again by the positive energy we received from the crowd.

We can’t even describe how much it meant for us to have you all come out to our venue that day: you folks really were the icing on the cake for us in working on this conference for the past 8 months or so. The atmosphere was warm and welcoming, and we couldn’t be happier to have shared a day filled with inspiration with all of you.

But all good things have to come to an end, and in wrapping up BubbleConf 2013, we’d like to list the photos, videos and reviews that were taken on that day.

Videos

The guys over at TayloredTales did an amazing job at capturing the day itself. The first video should give you an idea of what BubbleConf 2013 was like from an attendee’s point of view.

<iframe src="//player.vimeo.com/video/75995428" width="640" height="360" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>

The videos of the talks themselves that were held in the main room will be put up shortly as well. Please stay tuned, you really don’t want to miss out any of them!

Pics or it didn’t happen

Photos by Cuong Bui. Be sure to check out the entire gallery.











Reviews

Survey

If you’ve attended BubbleConf, please let us know what we got right/wrong, we’d love to know! You should have received a link to our survey via the mailinglist about this, but feel free to send in happy thoughts to us via email!

Stay Classy Amsterdam!

BubbleConf was born out of the desire to have a conference that would cater to startups in a multifaceted way by covering the topics we felt were most important for tech startups: tech, design and entrepreneurship. By putting these topics in wedlock, we had hoped to be able to bring together as many people from different fields to come share their war stories with one another. And possibly even form new startups. We felt there were so many diamonds in the rough in the Netherlands that really deserved a spot in the limelight: they would be able to do amazing things when given the right opportunities.

We’re incredibly excited to see that we have at least been able to accomplish a few of those goals that we set out to achieve when looking back at BubbleConf. We really hope our attendees will continue working on their projects and work towards putting the Netherlands/Europe on the startup map. We will certainly continue to do so with our own startup Phusion ;)

As for a 2014 edition of BubbleConf, that might be a bit too early to think about at this point: everyone involved from Nedap and Phusion are still recovering from the 8 months or so of time they put into organizing BubbleConf 2013. Regardless of whether or not there will be a 2014 edition, we hope you have enjoyed BubbleConf 2012 and 2013: we certainly did!

New ebook: Geocoding on Rails, Your Map to Geocoding Rails Applications

Posted 7 months back at GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS - Home

If you’ve worked on a web application in the past eight years or so, there’s a good chance you’ve written mapping or geocoding functionality. I’ve worked on multiple Rails applications in the past year which geocode certain pieces of data; each time, I had to remind myself which Ruby gems to use for searching, how to retrieve coordinate information from the browser, and the correct way to write tests for the behavior I wanted to add.

Introducing “Geocoding on Rails”

Today, I’m proud to announce thoughtbot’s newest publication, Geocoding on Rails, written by Laila Winner and myself. The 60 page ebook covers the following topics:

  • Which gems to use based on application requirements
  • How to build out a Rails application which geocodes data
  • How to use the W3C Geolocation and Google Geocoding APIs to reverse-geocode at a browser level
  • How to speed up responses with caching
  • How to test virtually every aspect of the app as it’s built

Includes the source code of a Rails app with easy to read code and high performing geospatial queries

The book includes a fully functional Rails application written in Rails 4 and Ruby 2 with a full test suite of RSpec acceptance tests (using Capybara), unit tests, and CoffeeScript unit tests using Konacha. Also included is a dataset with almost 11,000 Starbucks locations to get you started.

As with all our books, you initial purchase of the book gets you all future updates we make. We even give you access to the GitHub repository.

Get your copy of Geocoding on Rails today!

Available for Free with Learn Prime

If Geocoding on Rails interests you, you may want to check out our subscription service, Learn Prime.

For as little as $29/month, you get ongoing access to our books like Geocoding on Rails, screencasts, exclusive subscriber content, a forum to ask thoughtbot your toughest Ruby, Rails, and refactoring questions, and more. We also provide online workshops, and one-on-one mentoring.

Backbone.js, JSON API, and Relational Data: A Primer

Posted 7 months back at GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS - Home

While following patterns suggested by JSON API with Ember may be straightforward, little documentation exists for its usage within Backbone.js. With feed-readers popular in the past few months, I’ve decided to demonstrate how to follow the specification defined by JSON API to provide data to a Backbone application; namely, how to populate collections and models with associated data.

The Application API

Let’s start with the Rails application’s API implementation, which is fairly straightforward:

# app/controllers/api/feeds_controller.rb
class Api::FeedsController < ApplicationController
  respond_to :json

  def index
    feeds = Feed.rss
    respond_with feeds, each_serializer: FeedSerializer
  end

  def show
    feeds = Feed.where(id: params[:id]).rss
    respond_with feeds, each_serializer: FeedSerializer
  end
end

The controller is using ActiveModel::Serializers to generate JSON responses for both Feed and Entry objects.

# app/serializers/feed_serializer.rb
class FeedSerializer < ActiveModel::Serializer
  attributes :id, :title, :url, :feed_url, :etag, :description

  has_many :entries, serializer: EntrySerializer,
    embed: :ids, include: true, key: :entries
end

# app/serializers/entry_serializer.rb
class EntrySerializer < ActiveModel::Serializer
  attributes :id, :url, :title, :published, :author, :content

  def content
    object.content || object.summary
  end
end

These classes result in a JSON structure like this when retrieving api/feeds.json:

{
  "entries"=> [
    {"id"=>"a9f9283c34af5c6f7ab6fc461e5ba8ee",
      "url"=> "",
      "title"=> "",
      "published"=>"2013-09-22T18:25:02Z",
      "author"=>"",
      "content"=>""},
    {"id"=>"e805ed779257cd0d1f69b747fb01b591",
      "url"=> "",
      "title"=>"",
      "published"=>"2013-09-22T18:16:06Z",
      "author"=>"",
      "content"=> ""},
    {"id"=>"6601a53c98e690a46b8bbeca46a6904a",
      "url"=>"",
      "title"=>"",
      "published"=>"2013-08-30T15:16:03Z",
      "author"=>"",
      "content"=> ""}
  ],
  "feeds"=> [
    {"id"=>"e74786582200ea744c0d0a72fc616199",
      "title"=>"",
      "url"=>"",
      "feed_url"=>"",
      "etag"=>"\"4762e3773a5404de50dcfaef49697460\"",
      "description"=>"",
      "entries"=> ["a9f9283c34af5c6f7ab6fc461e5ba8ee", "e805ed779257cd0d1f69b747fb01b591"]},
    {"id"=>"1a33061dccfdc80aff5ce04df9591f6e",
      "title"=>"",
      "url"=>"",
      "feed_url"=>"",
      "etag"=>"\"7896d-eaef-4e6c07d3b7300\"",
      "description"=> "",
      "entries" => ["6601a53c98e690a46b8bbeca46a6904a"]}
  ]
}

There are two keys, feeds and entries, returned. Each item within feeds maintains a reference to its list of entry IDs, which will need to be associated when building up the structure within the Backbone collection.

The Backbone Application

Let’s look at the Backbone collection:

# app/assets/javascripts/collections/feeds.coffee
class @App.Collections.Feeds extends Backbone.Collection
  model: App.Models.Feed
  url: '/api/feeds'
  parse: (response) =>
    @entries = response.entries
    response.feeds

parse is doing most of the heavy lifting here, assigning a property entries to the collection (to be used later) and returning response.feeds, which gets assigned internally to models().

With the collection of feeds knowing about entries, it becomes the responsibility of each App.Models.Feed to correctly reference each App.Models.Entry:

# app/assets/javascripts/models/feed.coffee
class @App.Models.Feed extends Backbone.RelationalModel
  relations: [
    {
      type: Backbone.HasMany
      relatedModel: 'App.Models.Entry'
      collectionType: 'App.Collections.Entries'
      key: 'entries'
    }
  ]

  initialize: ->
    @set 'entries', _.filter @collection.entries, (entry) =>
      _.indexOf(@get('entries'), entry.id) >= 0

  title: ->
    @get 'title'

  description: ->
    @get 'description'

  entries: ->
    @get 'entries'

Within App.Models.Feed's initialize, we bootstrap the JSON data from the collection’s entries into the entries attribute on the App.Models.Feed model. Because the entries array may contain IDs of entries for other feeds, however, we filter out everything that doesn’t belong. Once the records have been filtered correctly, Backbone-relational.js handles the rest.

For reference, here are App.Models.Entry and App.Collections.Entries:

# app/assets/javascripts/models/entry.coffee
class @FeedMe.Models.Entry extends Backbone.RelationalModel
  title: ->
    @get 'title'

  url: ->
    @get 'url'

  published: ->
    @get 'published'

  content: ->
    @get 'content'

  author: ->
    @get 'author'

# app/assets/javascripts/collections/entries.coffee
class @FeedMe.Collections.Entries extends Backbone.Collection
  model: FeedMe.Models.Entry

Results

While there is a bit of wiring involved, it’s fairly easy to set up a Backbone app to interact with associated data provided by an API following the patterns of JSON API. If you’re using Marionette.js to handle associated data and have examples to share, tweet @thoughtbot to let us know!

Learn More About Backbone.js

If you’re interested in learning how to build Backbone apps, I recommend you check out thoughtbot’s book Backbone.js on Rails, which includes an example app in addition to the book itself.

Go grab a copy today!

Additionally, if you’re a Learn Prime subscriber, you’ll get access to the book for free. Learn Prime starts at $29/month and grants subscribers access to our books, screencasts, exclusive subscriber content, and more!

Build Phase Podcast Episode 10: Grandmas Are Twice as Efficient

Posted 7 months back at GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS - Home

Build Phase Podcast Episode 10: Grandmas Are Twice as Efficient :

Gordon Fontenot and Mark Adams talk about Cookie Clicker and review listener feedback.

Giant Robots Podcast Episode 68: Simplicity and Elegance

Posted 7 months back at GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS - Home

Giant Robots Podcast Episode 68: Simplicity and Elegance:

Ben Orenstein and Paul Farnell, CEO of Litmus, talk about starting up, business practices, and Litmus.

Lighthouse goodness

Posted 7 months back at entp hoth blog - Home

Howdy Lighthouse users! I come bearer of good news! We deployed a couple updates in the last few days. It particularly touches spam on public projects, but there are a number of other goodies that should make everyone happier.

Spam

A number of prominent public projects have been suffering a lot from spam, and it was time to alleviate the pain. So here are the changes we made:

  • If you are an account admin, you can now manage spam across your account by simply searching for spam:1. This will lead you to a dedicated view where you can mass delete/restore/preview content marked as spam, across all your projects. For big accounts, the first load may take a while, but after that it should work pretty well. If you have spammers with hundreds of post, we can clean them up for you, just email us at support@lighthouseapp.com.

  • We used to delete comments with a really high spam score. This was originally intended to limit spam but we found out the spam detection had some issues, and this resulted in false positives. Well no more! All content is created and kept, and you can review it on the spam page. This was the number one complaint we had, and it should now be a thing of the past.

  • As your mark content as spam/ham, we get notifications based on a number of parameters and heuristics. This means that in many cases, we’ll see when a legitimate user has been flagged as spam incorrectly, and when a spammer seems to be able to post unpunished. We’ll take care of those users appropriately so you don’t have to, and this should make for a smoother experience for everyone.

You can find more information on the KB: http://help.lighthouseapp.com/kb/project-management/managing-spam

Emails

  • It was a long time coming, but our notifications are now HTML emails. The style is simple and light, just like in Tender, and it should greatly improved readability.

  • Modifications to existing comments will now generate notifications. I realize this may not be ideal for a few users who edit comments a lot (and I apologize to them), but for the vast majority of users, this is a good thing. Many small changes on tickets went unnoticed before because there was no email.

  • The “Show me” dropdown now include every member of a project when on a project page. Before, it only included account admins. So if you have a lot of project members, and you want to see what they are into, this should help you out.

Conclusion

I hope this improves your Lighthouse experience, and I’ll be happy to hear your thoughts.

Cheers!