Rails on Maui

Programming in Paradise

Rocking With Tmux, Tmuxinator, Guard, Zeus, and iTerm2 for Rails Development

| Comments

What’s the most effective way to:

  1. Start several different processes for Rails, such as Zeus, Rails server, rspec, resque, and the scheduler.
  2. Have the output for each process in a separate tab.
  3. Not have the process pause when you scroll the output, as happens in tmux.

Here’s a short demo of using tmuxinator to get a project running in several iterm2 tabs:

Why Guard?

I use Guard for:

  1. Automatically running rspec tests based on changes in either tests or source files. Together with Zeus, I haven’t found a faster way to get immediate feedback from tests. Pro tip: Learn how to use :focus with your specs to configure exactly what tests to have guard run.
  2. Automatically restarting the server when needed. For example, if you change gems or routes, you need to restart the server.

While I love running Guard with Zeus, Spring is the default in Rails 4.1, so I’ll probably give that a try in the near future.

Why Tmuxinator and Tmux?

Tmuxinator is awesome for configuring the layout of several processes.

Here’s a sample tmuxinator file.

When I run the command

1
mux my_project

And then I see the following. This is way easier than opening up tabs in iTerm2 and running commands every time.

The main problem with this setup is that if you scroll a window backwards (using the tmux keyboard bindings), and you don’t un-scroll, then the process pauses, such as the Rails server. That’s super annoying. Often I’m running specs, and I want to scroll back to see a stack trace, but that prevents the continuation of the test run! Here’s a short discussion of the issue.

Capybara PhantomJs Poltergeist Rspec Tips

| Comments

I’ve added a page of tips on integration (aka feature spec) testing using Capybara, PhantomJs, Poltergeist, and Rspec.

Some of the tips include:

  1. Favorite test configuration (gems, spec_helper, etc.) for feature specs.
  2. How to troubleshoot and debug feature specs
  3. My setup for using Zeus with parallel-tests, including a rake task for setting up the databases.
  4. Tricky testing:
    1. Auto-complete dropdowns (some handy utility methods).
    2. Hover effects (easy now!)
    3. AJAX

I’ll try to keep this page of tips updated as my test configuration evolves.

Org-Mode Octopress Setup V2

| Comments

Note: This is a refresh of my original post from April, 2013 to adjust for Emacs 24.3 and org-mode 8.2.x

WordPress seemed like a good blogging platform, but it just didn’t feel right. I spend all my day editing text files using vim key-bindings, and I love Org Mode for all non-coding writing. If you don’t know Org Mode, it’s like having Markdown mode on steroids. You can have a numbered list in Markdown, but org-mode lets you re-order the list, and that’s just the beginning. Editing blog documents in the WordPress editor felt almost as bad as being told to use MS Word. I found that ergonomics of Org Mode, including all the goodness of recent versions of Emacs, including Evil (Vim emulation), just made organization of creative thoughts so much more enjoyable.

So I bit the bullet one weekend, and dove into Octopress, publishing my first article, Octopress Setup with Github, Org Mode, and LiveReload. The solution presented in that article Introducing Octopress Blogging for Org-Mode stopped working when I upgraded Emacs to 24.3 and org-mode to 8.2.x. Here’s a rehash of my original article updated to the latest software versions as of March, 2014.

If you used to writing real web applications, rather than know the intricacies of a giant monolithic blogging platform, then the customization of Octopress seems so much more straightforward. This is so much more like the Unix philosophy that so many of us love, which is small and modular, rather than monolithic.

Simple Form and Disabling Buttons on Submit by Default

| Comments

TLDR

Here’s an easy way to have all your SimpleForm submit buttons default to setting data-disable-with so that you don’t get errors when users double click on submit buttons. If you’ve gotten a few ActiveRecord::RecordNotUnique errors that were hard to reproduce, then here’s your solution, with our without SimpleForm. Additionally, using data-disable-with provides the user with nice feedback once a button is clicked.

ActiveRecord::RecordNotUnique Error!

If you’re using Devise, and you get a ActiveRecord::RecordNotUnique error when a new user is signing up, where do you look?

An ActiveRecord::RecordNotUnique occurred in registrations#create:

PG::UniqueViolation: ERROR: duplicate key value violates unique constraint
"index_users_on_email" DETAIL: Key (email)=(somebody@yahoo.com) already
exists. : INSERT INTO "users" ("address", "city", "confirmation_sent_at",
"confirmation_token", "created_at", "default_location_id", "email",
"encrypted_password", "first_name", "last_name", "mobile", "role", "state",
"updated_at", "zip_code") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11,
$12, $13, $14, $15) RETURNING "id"

At first, I was concerned that my unique index on my users table is not case insensitive. I started going down the road of converting my normal unique index on users.email to this index:

1
CREATE UNIQUE INDEX users_email_ci_idx ON users ((lower(email)));

However, I soon figured out that Devise was already always saving email in the database in lower case via a before_validation hook.

So then I tried to double click the SAVE button, and, BOOM, I got the same error.

data-disable-with=’Processing…’

A little bit of googling quickly revealed some handy rails techniques disabling a submit button after being clicked, namely the setting of attribute data-disable-with: “Some Message…” on both links and buttons. This works nicely to fix the double submit RecordNotUnique error, and it provides some sweet user feedback upon clicking a button. Here’s an example of a SAVE button.

Immediately after clicking the SAVE button, the button disables and the text changes.

Buttons

Example and API: button_tag

1
<%= button_tag "Checkout", data: { disable_with => "Please wait..." } %>

Links

Example and API: link_to

1
<%= link_to "Profile", profile_path(@profile), data: { disable_with: "Processsing..." } %>

SimpleForm Submit Buttons

Even better, this can be done in one place for all SimpleForm submit buttons!

In a file like config/simple_form.rb, place this initialization code:

1
2
3
4
5
6
7
8
SimpleForm::FormBuilder.class_eval do
  def submit_with_override(field, options = {})
    data_disable_with = { disable_with: 'Processing...' }
    options[:data] = data_disable_with.merge(options[:data] || {})
    submit_without_override(field, options)
  end
  alias_method_chain :submit, :override
end

What the bit of code above does is that it:

  1. Opens up the FormBuilder class to add a method submit_with_override.
  2. Modifies options hash’s :data element, setting a default value for key disable_with that will not apply if there’s already a value there, thus allowing the default to be overridden by any individual button.
  3. Calls alias_method_chain which makes is so that a call to submit actually calls submit_with_override and that method can call submit_without_override, which is the original submit method. The pattern of naming the methods with_override and without_override is part of the alias_method_chain call. Pretty darn cool!

Here’s a sample sign-up form that overrides the default “Processing…” label when the SAVE button is clicked.

1
2
3
4
5
6
7
.box.clearfix.box-last
  = simple_form_for resource, as: resource_name, url: registration_path(resource_name), html: { class: ""}  do |f|
    = f.error_notification
    = f.input :first_name, required: false, autofocus: true, label_html: { class: "label-required"}, input_html: {class: ".col-md-4" }
    = f.input :last_name, required: false, label_html: { class: "label-required"}, input_html: {class: ".col-md-4" }
    = f.input :email, required: false, label_html: { class: "label-required"}, input_html: {class: ".col-md-4" }
    = f.button :submit, "SAVE", class: "submit", data: { disable_with: "Creating New Account..." }

Now go and click on some of your submit buttons, and they will all disable and display “Processing…”. On a remote form that returned js.erb, I had to send back this line to reset the submit button:

1
$("#js-some-button").removeAttr("disabled").attr('value', 'ORIGINAL BUTTON TEXT');

Using RubyMine/IntelliJ Regexp Search/Replace

| Comments

RubyMine’s interactive search/replace is awesome. The Regexp feature is especially useful. Not only will it help you edit faster, but it will improve your ability to write RegExp’s in your code. When do you need to use a regexp? Whenever a standard find/replace won’t cut it. For example, if you changing the rspec syntax from one form to another, such as from:

1
2
let(:my_subject) { something }
it { expect(my_subject.value).to eq(some_value) }
1
2
subject { something }
its(:value) { should eq(some_value) }

The following screencast shows how you can interactively use the Regexp feature to figure out the right regexp to search for as well as the right replacement.

In this example, I’m replacing one rspec syntax with a replacement one.

it \{ expect\(my_subject\.(\w+)\)\.to eq\((.*)\) }

Replace with:

its(:$1) { should eq($2) }

Here’s a few key tips:

  1. Be sure to first check the regexp check-box if you’ll need that.
  2. As you type each character into the search box, observe if you’re increasing your match area to get what you want.
  3. If a character doesn’t match, then try escaping the character. For example, I had to escape the { and ( as those characters have special meaning in the regexp.
  4. Once you get a match with the right groupings for replacement, then put in the $1, $2, etc. into the replacement box to refine your replacement string.
  5. Then hit Opt-P (or Alt-P) to replace.

This is best shown with this 2 minute screencast.

Migrating From Bash to Zsh

| Comments

I migrated from Bash to Zsh in October and I’m quite thrilled with zsh.

Motivation

What motivated me to finally move?

  1. I no longer used the shell within Emacs. If you have a bash setup that works well in Emacs, don’t try to switch. Since moving from emacs bindings to evil-mode, I am quite comfortable in Vim, so I find myself using iTerm way more than the Emacs shell.
  2. While doing some pair programming with @jakeonrails, I saw the coolness of zsh, which he pointed out to me “was no big deal”, just what’s on the Railscasts Episode on Oh My ZSH.

Tips on Migrating

Here’s a few tips to somebody migrating might find useful:

  1. Try out oh-my-zsh and take a look at the themes examples. The themes seem to be all customizations of the prompt. I’ll share what I came up with at the bottom, which is a modification of the default robbyrussell theme.
  2. While most of your bash code will migrate as-is, this is a good time to clean up some cruft in your files. I like to organize my shell code into small files, each with a particular theme, and then have the .zshrc source those, rather than having a giant .zshrc file.
  3. The oh-my-zsh plugins are way for you to share shell configuration with other members of the community. It’s simple to read what those plugins are doing. Many are just setting aliases. I started to migrate my own configuration code by converting to plugins, but then I realized that that’s overkill. If I ever want to share the configuration, at that point, I can convert to a plugin, which is quite simple.
  4. If you have any shell functions that use [, you might have escape that character for zsh.
  5. If you install zsh plugins, be very careful with any newly installed aliases from the plugins. I previously had gl aliased as ‘git log’ and the git plugin uses gl for git pull, which caused me a huge headache when I ran that within my octopress branch.
  6. You need to escape the ^ character for commands such as git reset HEAD\^

Migration Notes

Escape []

In the third line of this function, I had to escape the [ and the ].

1
2
3
4
5
6
7
8
9
10
opost() {
  cd $OCTO_HOME
  output=$(rake new_post\["${1}"\])
  new_file=$(echo $output | awk '{print $4}')
  base=$(basename $new_file)
  new_location=$OCTO_HOME/source/org_posts/
  mv $OCTO_HOME/$new_file $new_location
  echo created $new_location$base
  cd -
}

My new zsh prompt

To set this up, I created a custom theme called justin808 by doing the following:

  1. Create a theme file oh_my_zsh/custom/justin808.zsh-theme. See below.
  2. Export the theme name.

This is what it looks like in my .zshrc file. The first line is because I moved my ZSH configuration files.

1
2
export ZSH=$HOME/.oh-my-zsh
export ZSH_THEME="justin808"

Here is my theme file oh_my_zsh/custom/justin808.zsh-theme

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
hostname=`hostname`
if [ $hostname != "$HOME_HOST" ] || [ $USER != "justin" ]; then
  host_stuff='%n@%m:'
else
  host_stuff=''
fi  
PROMPT='%{$fg_bold[red]%}➜ %{$fg_bold[green]%}%p ${host_stuff}%{$fg[cyan]%}${PWD/#$HOME/~} %{$fg_bold[blue]%}$(git_prompt_info)%{$fg_bold[blue]%} % %{$reset_color%}'

# display exitcode on the right when >0
return_code="%(?..%{$fg[red]%}%? ↵%{$reset_color%})"

RPROMPT='${return_code}$(git_prompt_status)%{$reset_color%} [%*]'

# RPROMPT='[%*]'
ZSH_THEME_GIT_PROMPT_PREFIX="(%{$fg[red]%}"
ZSH_THEME_GIT_PROMPT_SUFFIX="%{$reset_color%}"
ZSH_THEME_GIT_PROMPT_DIRTY="%{$fg[blue]%}) %{$fg[yellow]%}✗%{$reset_color%}"
ZSH_THEME_GIT_PROMPT_CLEAN="%{$fg[blue]%})"
GIT_PS1_SHOWUPSTREAM=verbose

ZSH_THEME_GIT_PROMPT_ADDED="%{$fg[green]%} ✚"
ZSH_THEME_GIT_PROMPT_MODIFIED="%{$fg[blue]%} ✹"
ZSH_THEME_GIT_PROMPT_DELETED="%{$fg[red]%} ✖"
ZSH_THEME_GIT_PROMPT_RENAMED="%{$fg[magenta]%} ➜"
ZSH_THEME_GIT_PROMPT_UNMERGED="%{$fg[yellow]%} ═"
ZSH_THEME_GIT_PROMPT_UNTRACKED="%{$fg[cyan]%} ✭"

GoGaRuCo 2013: Community > Code

| Comments

This past weekend was my first GoGaRuCo. Here’s a perspective from a newbie, along with lots of photos.

The number one thing I discovered is that GoGaRuCo, like Ruby, is not just about code. It’s about the awesome people and the community.

If you just want to see the talks at GoGaRuCo, don’t attend. All of the talks will be available on web shortly. So why did the conference sell out, with about 200 wait-listed people begging to attend?

GoGaRuCo attendees are madly passionate about programming, especially in Ruby. Most attendees work at start-ups, at web consulting firms, or as freelancers. The common thread is that we all love to program. It’s not work. It’s a passion. And it’s artistic, cutting-edge, relevant, and fun!

Amongst the community, there’s a genuine feeling that we’re all in this together, and the more we can help each other, the better off we and the world will be. This is truly the open source spirit of contributing whatever code you can give back to the community. Consequently, for me, attending the conference was about meeting others who contribute to open-source and learning more about how I can contribute. As a bonus, I got a chance to personally meet the people whom I follow on Twitter, read their blogs, and use their open source.

My Top 14 for 2013 GoGaRuCo

  1. Won’t need to buy any new T-shirts for a long time.
  2. Got a poster tube that doubles as a form for caissons.
  3. No stress over picking which talks to attend, with one track.
  4. Can, but won’t, write my own replacement for ActiveRecord and IRB.
  5. Will finally be able to solve the Rubik’s cube (soon).
  6. Now understand why privacy from the NSA really does matter to me.
  7. Can write Ruby to fly a surveillance drone.
  8. Got tips on the performance tuning one of the biggest open source rails applications, Discourse.
  9. Everything I wanted to know about Ruby, and my co-worker’s compensation, but was afraid to ask.
  10. Who is @JEG2?
  11. Plenty of break time between talks made for lots of conversation.
  12. Personally met many of the folks I follow on Twitter!
  13. Most folks I met want to visit me in Maui at my B&B Sugar Ranch Maui!
  14. Met the most talented and interesting group of programmers anywhere, who all love Ruby and programming just as much as I do.

Tips

  1. Don’t miss the pre-parties, breakfasts, or after-parties.
  2. Don’t plan to work during the conference, and leave your laptop at home. An good mobile phone or tablet is very useful.
  3. Sign up early if hanging out with other passionate programmers is your idea of fun!

Ruby on Maui, 2014?

If you interested in attending a small Ruby conference in Maui next year, maybe in May, please get in touch with me.

Photographs

If you’d like full resolution, non-watermarked copies of any of the images, please get in touch with me. I personally cropped and adjusted the exposure on all images. These were taken with a Nikon D5100, SB-400 AF Flash, and a very basic Nikon 18-55mm lens.

I hope that folks tag themselves in the Facebook albums! And please share them.

Flickr

I uploaded the full set of 2560 pixel images here. This has the half not shown on Facebook.

  • First 200: Pre-party, conference day 1, some of first after-party.
  • Next 200: Conference day 2.
  • Last 134: Conference day 2 and second post-party.

Upgrading Octopress

| Comments

One of the criticisms of Octopress is how there’s no clear separation of the static generation engine and the content of one’s website, and thus upgrading Octopress is difficult. I delayed upgrading due to this. However, my concerns were unfounded, as it was very painless to upgrade Octopress.

The instructions boil down to this short help page on Updating Octopress:

1
2
3
4
git pull octopress master     # Get the latest Octopress
bundle install                # Keep gems updated
rake update_source            # update the template's source
rake update_style             # update the template's style

The first step resulted in a few merge conflicts. I find RubyMine’s git conflict resolution tools helpful, so I used those. Here’s a short screencast (embedded below) showing you how these tools helped with this process. Besides some minor issues dealing with a few merge conflicts, there was nothing very interesting or eventful about the upgrade, which means that the current process is really quite OK.

I hope a few people find this demo of the RubyMine git conflict resolution tool helpful. The key takeaways from this video are:

  1. Merge conflicts show up as red in the list of changes.
  2. Try the diff’ing buttons in the upper left to get 2 way views of the 3 way merge.

3, “Yours” means your local changes, and “Theirs” means the server’s changes, or, in this case, the changes in the main Octopress development branch.

Did the upgrade work? You’re looking at the results of it.

It’s worth noting that I had one slight snag. When I merged sass/screen.scss, I accidentally removed this line, which is used for the youtube plugin.

1
@import "custom/rve";

I could have figured this out by examining the history of the file and noting that I had added this line, rather than it being part of Octopress. So yes, it would be bit better if there was a cleaner separation between the Octopress code and any enhancements. However, the current mechanism works, and it’s still thousands of times better than WordPress.

Migrating From Capybara-Webkit to Poltergeist-PhantomJs

| Comments

Motivation

Today I migrated a medium size test suite from capybara-webkit to Poltergeist with PhantomJS. I had two main motivations for switching:

  1. PhantomJS is more sensitive to avoiding false positives. For example, in the past, one could click on non-visible DOM elements with capybara-webkit. While this may not currently be true with the latest Capybara, I’ve had good luck with PhantomJS in the past.
  2. Speed. When I last checked, PhantomJS was faster. Speed is critical for slow feature tests.

Here’s one reason that Poltergeist is more accurate and sensitive to failure:

When Poltergeist clicks on an element, rather than generating a DOM click event, it actually generates a “proper” click. This is much closer to what happens when a real user clicks on the page - but it means that Poltergeist must scroll the page to where the element is, and work out the correct co-ordinates to click. If the element is covered up by another element, the click will fail (this is a good thing - because your user won’t be able to click a covered up element either).

Tips for Migrating

Upgrade Gems First

At first, I lost time due to timing issues where I was clicking on elements of a hidden dialog that was not finished showing. Capybara-webkit was not bothered by the fact that the dialog was actually hidden and being loaded. PhantomJS bombed out. However, after I worked around the issue, I realized that my gems were outdated. Since you’re going to be fixing a bunch of tests anyway, it makes sense to get on the latest versions of the testing gems. The gems you want to upgrade are: rspec, rspec-rails, Capybara, and poltergeist.

Visible Option

After upgrading the gems, my workarounds were no longer necessary. However, the change from Capybara 2.0 to 2.1 had a big change in the way that it handles finding dom elements that are not visible. Previously, Capybara would not care if the dom element was hidden. For my tests, this resulted in breaking any tests that queried any non-visible DOM elements, such as scripts, meta tags, and links.

The key thing to be aware of is that you might get this obscure error message, and the fix is to add the visible: false optional parameter so that Capybara is not filtering by visible: true. The visible parameter is available to most finder methods in Capybara.

The obscure error you might see is something like this:

#=> Capybara::ExpectationNotMet Exception: expected to find xpath "//title" with text "Title Text." but there were no matches. Also found "", which matched the selector but not all filters.

The reason is the title element is not visible, and “visible” is the “not all filters” part of the error message.

Debugging Capybara Tests

The main reasons that previously passing feature tests will fail when migrating to Poltergeist is due to timing and visibility. The two main techniques for debugging Capybara tests are:

  1. Using screen shots (render_page below)
  2. Using HTML dumps (=page! below)

Keep in mind that these methods will not wait for elements to load. Thus, you should either have a Capybara statement that will wait for some DOM element to load or you might want to put in a sleep 10 to sleep for 10 seconds before capturing the screen shot or dumping the HTML.

If you use the helper methods specified below, and you should be able to work through why Poltergeist is not doing what you think it should be doing. So far, I haven’t yet run into a case where I have not found out that it’s been my fault rather than a bug in Poltergeist that’s caused a failure due to the migration. In many cases, you’ll be somewhat pleasantly surprised that you’ll be fixing a false positive.

Capybara’s Wait Strategy

Be sure to carefully read the Capybara documentation, especially the part titled “Asynchronous JavaScript”. That section explains how Capybara cleverly will wait until the page or ajax call finished so that the element expected appears. There’s a configurable timeout (Capybara.default_wait_time) for changing the default wait time before a test bombs out.

Xpath Tip

Be sure to understand the difference between //something and .//something. The later can be used inside a within block. The former will find the tag anywhere on the page, even when used inside of a within block!

Setup and Utility Debugging Methods

Here’s the setup and a couple utility methods that I use. Put these in a file in your helpers directory, such spec/helpers/capybara.rb.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Capybara.default_wait_time = 8 # Seconds to wait before timeout error. Default is 2

# Register slightly larger than default window size...
Capybara.register_driver :poltergeist do |app|
  Capybara::Poltergeist::Driver.new(app, { debug: false, # change this to true to troubleshoot
                                           window_size: [1300, 1000] # this can affect dynamic layout
  })
end
Capybara.javascript_driver = :poltergeist

# Saves page to place specfied at name inside of
# test.rb definition of:
#   config.integration_test_render_dir = Rails.root.join("spec", "render")
# NOTE: you must pass "js:" for the scenario definition (or else you'll see that render doesn't exist!)
def render_page(name)
  png_name = name.strip.gsub(/\W+/, '-')
  path = File.join(Rails.application.config.integration_test_render_dir, "#{png_name}.png")
  page.driver.render(path)
end

# shortcut for typing save_and_open_page
def page!
  save_and_open_page
end

Ember.js Tutorial With Rails 4

| Comments

The first post in this series, Ember.js Hello World, shows Ember working without a persistence backend. This post covers setting up Rails4 as the persistence engine behind that example, plus adding and deleting records. The amount of Ember and Rails code to make this example is almost completely included in this article. It’s that tiny!

The source code for the completed example can be found on GitHub: justin808/ember-js-guides-railsonmaui-rails4. I carefully crafted the commits to explain the steps.

You can try out the application on Heroku at: http://railsonmaui-emberjs-rails4.herokuapp.com/

I put many more details in this comprehensive screencast of how to go from a brand new Rails 4 app to an Ember.js app deployed on Heroku.

Key Tips

  1. Be sure to update the ember and ember-data javascript files with the command from the ember-rails gem (see below). Keeping these files at appropriate versions is key while the API is changing, especially for ember-data.
  2. If you specify the Router property for both model and setupController, you can have some very confusing results (details below).
  3. Get comfortable with Ember’s naming conventions. Ember does a ton with default naming. It’s basically got the same philosophy of “Convention over Configuration” of Rails. So it’s especially important to try to grok when the Ember examples are doing something implicitly versus explicitly. This is a bit like Rails. At first it seems like magic, like “How the heck is that happening”, and then one gets accustomed to the naming conventions and appreciates how much code it saves.
  4. Be mindful that some Ember.js commands run asynchronously, such as commit.

How Much Client Side JavaScript in Rails 4?

| Comments

Articles and Quick Summaries:

Why Discourse uses Ember.js:

Ask yourself how interactive your web application needs to be. On the less interactive side of the scale, there are huge wins with server side rendered HTML. The more interactive your application becomes, the more you’ll benefit from a client side MVC framework.

CoffeeScript Chrome Extensions

| Comments

Here’s 3 useful tools for using CoffeeScript for web development, possibly with Rails and EmberJs. All 3 tools are useful for different purposes.

CoffeeScript Source Maps: Debugging CoffeeScript Directly

With Source Maps, you don’t have to mentally convert your CoffeeScript code into JavaScript code in the debugger. Instead, you can now see your CoffeeScript code, even with correct line numbers. This rails gem, coffee-rails-source-maps, makes it easy to include CoffeeScript source maps as part of your rails application. Note, the Rails.env.development? is hard coded, so this only works when you use that specific environment. You can also do it manually, by using the -m flag with the coffee command.

Try CoffeeScript Chrome Extension: Converting between CoffeeScript and JavaScript

The Try CoffeeScript Enhanced Chrome extension is pretty nice for converting between JavaScript and CoffeeScript. The main advantage over http://js2coffee.org is that the you don’t have to open a new browser tab, and you can enter either CoffeeScript or JavaScript.

Coffee Console Developer Tool: Executing CoffeeScript in Chrome

Coffeeconsole: A Chrome Extension” provides a place to execute CoffeeScript in the Web Inspector.

Ember.js Hello World

| Comments

TLDR

  1. Tom Dale’s Intro Tutorial Video on EmberJs is awesome.
  2. Git repos of the start and the finish of the Tom Dale EmberJsTutorial.
  3. Tips for reproducing it.
  4. Screencast of me explaining the completed example.

Details

Ember.js is really amazing. The place to start is Tom Dale’s Intro Tutorial Video (on Youtube). In the 30 minute video you build the app shown here in this iframe. Some of the features you’ll learn include:

  1. Basic setup for an Ember.js app.
  2. Nested views. You can click on the articles on the left, and see the articles on the right.
  3. Ember helpers which provide markdown and date conversion with a tiny bit of code.
  4. Even how to do a read/write REST interface.

If a picture is worth a thousand words, here’s what you build in the video (you can try in the iframe below or a separate tab). The dynamic mvc nature of the bindings is neat. Try this:

  1. Click on the article “Octopress” on the left.
  2. Click Edit, change the markdown in the 2nd field, and see it change below dynamically!

Then try out the “Ember Inspector for Chrome”. Yehuda does a nice demo of it on youtube (more here). You can follow the installation instructions from Kasper Tidemann. Basically you want to install the chrome extension files from github.com/tildeio/ember-extension.

Once you do that, you can browse to open the sample on separate tab and see this:

You can click on most of the purple text to dig into the ember objects:

You can view <computed> values:

To make it easier for you, I created git repos of the start and the finish, minus the REST interface.

To maximize your learning efficiency:

  • Start with the files in the starter repo that I created. The Ember.js files are still changing, so your combination of js files is critical. There’s heaps of comments on the youtube video about how frustrating it can be to have the wrong combination of js files.
  • Try building the app yourself by following the video. If you’re short on time, watch the demo once and say “that’s damn cool”. But you won’t truly absorb the content without following along. Plus, it’s super cool to enter some statements in the console and see the magic of ember happen. (16:52 in the video).
  • When you have an error in your code (which you will if you’re practicing this), you need to know that you look for errors in the browser’s console.

Explanation of the Completed Code