Nepal on Rails

millisami's rants!

Railsconf 2014, Talks I Liked

Here I am listing the talks from Railsconf 2014 that I liked watching. It certainly doesn’t mean that other talks are not good, I list my likes here as I watch the episodes.

  1. Keynote – Writing Software by DHH
  2. Demystifying Data Science: A Live Tutorial by Todd Schneider
  3. Keynote: 10 Years! by Yehuda Katz

Updated – June 3, 2014

  1. Ultra Light and Maintainable Rails Wizards
  2. Workshop – Simplifying Code: Monster to Elegant in N<5 steps
  3. Rack::Attack: Protect your app with this one weird gem!
  4. Make an Event of It
  5. Real-time Rails With Sync
  6. How to Build a Smart Profiler for Rails
  7. Workshop – Applications First, Frameworks Second: Better Systems through Design
  8. Writing Small Code
  9. Lightning Talks
  10. Workshop – Taming Chaotic Specs: RSpec Design

Stubbing Network Calls (Api) Using Dyson for Emberjs Apps

Testing emberjs apps is the current buzzing topic. Here I try out my way to stub network calls while doing emberjs integration tests.

There are many libraries popping out in this field. e.g. ember-testing-httpRespond, jquery-mockjax, etc.

Here I would like to try out dyson. Its a nodejs app with simple DSL. Though it has its fake data generator dyson-generators, but I find that it has limited generators. So, for fake data generation, we’ll be using Faker which has massive amounts of fake contextual data.

Lets whip up one for our next ambitious fake API.

Clone the repo

We’ll use the dyson-demo repo for our own api.

git clone git@github.com:webpro/dyson-demo.git articles-api
cd articles-api
npm install
npm install Faker --save
echo 'node_modules/' > .gitignore
git add .gitignore
git commit -m 'node_modules folder git ignored'

Start the server with npm start. It starts the server on port 3000 by default, which can be customized in file dyson-demo.js

Visit http:localhost:3000 to list the stubbed endpoints. You will see some demo end points which you can wipe it out or keep.

Setup our API endpoint

Here, we will use Article as our example resource. To list the articles end point in the browser, first we’ll have to make an entry in the file services/get/_index.js

1
2
3
4
5
var examples = [
  '/articles',
  ....
  ....
]

Now we have to add a template for articles. Create the file.

services/get/articles.js
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
var g = require('dyson-generators');
var f = require('Faker');
var currentId = 0;

var articles = {
  path: '/articles',
  collection: true,
  size: 30,
  template: {
    id: function() {
      currentId += 1;
      return currentId.toString();
    },
    title: function() {
      return "Article #" + this.id;
    },
    body: f.Lorem.paragraphs()
  },
  container: {
    articles: function(params, query, data) {
        return data;
    }
  }
};

module.exports = [articles];

For dyson to pick up the changes, we should re-start the server. Then if we click the /articles or visit http://localhost:3000/articles, the output should look like the following.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
  "articles": [
    {
      "id": "1",
      "title": "Article #1",
      "body": "iure consequuntur numquam fugit inventore repudiandae\nfacere qui vel aut veniam eaque dolore incidunt\nnam vero rem expedita qui corporis voluptatum fuga distinctio\nomnis nihil et\n \r\tquam ipsam similique perferendis\nvoluptas ad voluptatem ut voluptatibus quia eius\nreprehenderit commodi repellendus iste\naccusamus error omnis asperiores qui\nqui distinctio quidem modi ullam quia voluptatem\n \r\tharum quia modi officia ea odio autem\nomnis reprehenderit autem molestiae\nquidem numquam iusto voluptatem"
    },
    {
      "id": "2",
      "title": "Article #2",
      "body": "iure consequuntur numquam fugit inventore repudiandae\nfacere qui vel aut veniam eaque dolore incidunt\nnam vero rem expedita qui corporis voluptatum fuga distinctio\nomnis nihil et\n \r\tquam ipsam similique perferendis\nvoluptas ad voluptatem ut voluptatibus quia eius\nreprehenderit commodi repellendus iste\naccusamus error omnis asperiores qui\nqui distinctio quidem modi ullam quia voluptatem\n \r\tharum quia modi officia ea odio autem\nomnis reprehenderit autem molestiae\nquidem numquam iusto voluptatem"
    },
    ........
    ........
    {
      "id": "30",
      "title": "Article #30",
      "body": "iure consequuntur numquam fugit inventore repudiandae\nfacere qui vel aut veniam eaque dolore incidunt\nnam vero rem expedita qui corporis voluptatum fuga distinctio\nomnis nihil et\n \r\tquam ipsam similique perferendis\nvoluptas ad voluptatem ut voluptatibus quia eius\nreprehenderit commodi repellendus iste\naccusamus error omnis asperiores qui\nqui distinctio quidem modi ullam quia voluptatem\n \r\tharum quia modi officia ea odio autem\nomnis reprehenderit autem molestiae\nquidem numquam iusto voluptatem"
    }
  ]
}

So, now we got our api that responds to /articles. To get better understanding of dyson, you can look out the examples that it already exists in the repo. You can also see the README of Faker.js to find various fake data generators.

I’ve pushed the repo at https://github.com/millisami/articles-api for future reference.

In the next part, we’ll write an Ember app integration testing using this api.

Deploy Emberjs App on Heroku

Updated (2014-03-01) due to recent changes into Tapas with Ember

Lets say that your app is now in deployable phase and want to do a quick deploy. The Tapas with Ember brunch has a section on deploying using rubygem Mina. But that deploy method needs a VPS which you might get it later, but not now. So, in the quest of a simple, quick and buck-free way, I figured out a way to deploy it on Heroku.

Lets whip-up a demo app using brunch:

brunch new gh:mutewinter/tapas-with-ember deployapp
28 Feb 17:48:25 - log: Cloning git repo "git://github.com/mutewinter/tapas-with-ember.git" to "deployapp"...
28 Feb 17:48:40 - log: Created skeleton directory layout
28 Feb 17:48:41 - log: Installing packages...
.....

Initialize the git repo and commit it.

cd deployapp
git init .
git add .
git commit -m 'Initial commit'

Since its a static javascript app, we’ll use Node.js to serve our app. For this, we will use express to serve the app.

npm install express --save

This will install the express and bower packages, their dependencies and updates the package.json file. As of this commit, handlebars is moved to be managed by bower due to this issue.

Then lets create the server directory and create the server/server.coffee file.

mkdir server
server/server.coffee
1
2
3
4
5
6
7
8
9
10
11
express = require('express')

app = express()

app.configure ->
 app.use(express.logger('dev'))
 app.use(express.bodyParser())
 app.use(express.static('public'))
 app.use(express.cookieParser())

app.listen(process.env.PORT || 5151)

Now, we need to add a "postinstall": "bower install; cake build" configuration inside scripts section in package.json file.

package.json
1
2
3
4
5
6
7
...
"scripts": {
  "start": "cake server",
  "test": "./node_modules/.bin/testem",
  "postinstall": "bower install; cake build"
},
...

When heroku starts to deploy the app, it will invoke the command cake build that compiles the emberjs app and place it into the public folder. And the 5th line of server/server.coffee file configures the express server to load the apps file from this public folder.

We need to configure the heroku to run this server/server.coffee file. So, we will create a Procfile in the root of the project.

Procfile
1
web: coffee server/server.coffee

Lets commit the changes.

git add .
git commit -m 'Setup for heroku deploy'

Now we’ll create the heroku app. For the following heroku command, you’ll need to install the Heroku tool belt first.

heroku apps:create deployed-ember
Creating deployed-ember... done, stack is cedar
http://deployed-ember.herokuapp.com/ | git@heroku.com:deployed-ember.git
Git remote heroku added

The above command creates the app named deployed-ember and setup the git remote handle named heroku. Actually, I tried with the name deployapp, but it was already taken, so had to opt in for deployed-ember. You can name-the-app anything you want unless its already taken. The app is now ready to be deployed with the single git push command.

git push heroku master
....
....
-----> Launching... done, v5
       http://deployed-ember.herokuapp.com deployed to Heroku

And if all went well, then the app should be hosted at http://deployed-ember.herokuapp.com

At this time of writing, I’ve noticed that the CSS design of the app in development and on Heroku has some differences. Or we might say: Heroku style bug. This happens because Heroku’s node buildpack puts node and npm in the vendor directory. After the discussion on this thread, came up with the following fix.

Open up the config.coffee file at the project root and change the stylesheets section to the following:

config.coffee
1
2
3
4
5
  ...
  stylesheets:
    joinTo:
      'styles/app.css': /^(app|bower_components|vendor\/(?!node))/
  ...

Now you commit this change and re-deploy the app:

git commit -am 'Heroku style bug fix'
git push heroku master

and you shall see both the development and Heroku build is alike.

For the reference, I’ve pushed this repo to Github as well.

Drag N Drop With Emberjs, Part 2

This is the part 2 for the earlier post Drag and drop with Emberjs. In this post, our objective is to:

  • Update the Total cart price when a product is dropped into the cart
  • List the products added in the cart

When a product is dropped over the cart, we need some kind of array into which we’d push the record. So, lets set the line_items array in the controller to hold the cart products. Create a controller file:

app/controllers/index.coffee
1
2
module.exports = App.IndexController = Ember.ArrayController.extend
  line_items: []

Now whenever a product is dropped into the cart, lets push that object.

1
@get('controller').get('line_items').pushObject(record)

So now our cart view looks:

app/views/cart.coffee
1
2
3
4
5
6
7
8
9
module.exports = App.CartView = Ember.View.extend
  templateName: 'cart'
  classNames: ['basket']
  dragOver: (ev) ->
    ev.preventDefault()
  drop: (ev) ->
    id = ev.dataTransfer.getData('text/data')
    record = @get('controller').findProperty('id', Number(id))
    @get('controller').get('line_items').pushObject(record)

To list the items added into the cart, we need to update our cart template.

app/templates/cart.hbs
1
2
3
4
5
6
7
<div class="line_items">
  {{#each line_item in line_items}}
    <div class="line_item">
      {{line_item.title}} <span>{{line_item.price}}</span>
    </div>
  {{/each}}
</div>

Now, whenever a product is dropped into the basket, the item is listed in the view.

To keep the track of the total price, we need to declare a computed property into the controller that computes the total price of the basket. So, in the cart template, lets add total_price

app/templates/cart.hbs
1
2
3
4
5
6
7
8
9
10
11
12
<div class="total">{{total_price}}</div>
<div class="shop_cart">
  <span>Drop the product here</span>
</div>

<div class="line_items">
  {{#each line_item in line_items}}
    <div class="line_item">
      {{line_item.title}} <span>{{line_item.price}}</span>
    </div>
  {{/each}}
</div>

And add this into the index controller.

app/controllers/index.coffee
1
2
3
4
5
6
7
8
9
10
module.exports = App.IndexController = Ember.ArrayController.extend
  line_items: []

  total_price: (->
    total = 0
    if @get('line_items').length > 0
      @get('line_items').forEach (line_item) ->
        total += line_item.price
    total
  ).property('line_items.@each')

This concludes the bare minimum we can do to achieve the drag and drop functionality with Emberjs. There are many things that can be added to extend the functionality of this app, but its out of the scope of this post.

I’ve updated the repo where it has thing like, filtering the items and its quantity with some styles.

In the next post, I’ll be writing on how to deploy the ember app built with rapid development workflow onto heroku as node app to host the production app.

To stay updated, just follow @nepalonrails

Drag and Drop With Emberjs

There were good old days on how to implement drag-n-drop UI. But now we’re at better stage. Its a piece of cake to impelement it using Emberjs. So lets build it with the rapid emberjs development workflow.

Lets start.

brunch new gh:mutewinter/tapas-with-ember drag-n-drop
cd drag-n-drop
git init
git add .
git commit -m 'Initial commit'

Start the server with cake server and visit http://localhost:3333

Objective

  1. List of Products
  2. Make it draggable
  3. Cart where user can drop the product into
  4. Update the cart’s total price when dropped into the cart

First, lets add and list the products in the model.

app/routes/index.coffee
1
2
3
4
5
6
7
module.exports = App.IndexRoute = Ember.Route.extend
  model: ->
    [
      {id: 1, title: 'Mac Book', price: 2000},
      {id: 2, title: 'Dell Inspiron', price: 2120},
      {id: 3, title: 'Lenovo', price: 1200}
    ]

To list the products, add the following content.

app/templates/index.hbs
1
2
3
4
5
6
7
<h2>Welcome to Store</h2>

<div class="products">
{{#each product in controller}}
  {{view App.ProductItemView contentBinding="product"}}
{{/each}}
</div>

Now we need the ProductItemView.

app/views/product_item.coffee
1
2
3
4
5
6
7
module.exports = App.ProductItemView = Ember.View.extend
  templateName: 'product_item'
  attributeBindings: ['draggable']
  draggable: "true"

  dragStart: (ev) ->
    ev.dataTransfer.setData('text/data', @get('content.id'))

And this is the template.

app/templates/product_item.hbs
1
2
3
4
<div class="product">
  <span class="title">{{product.title}}</span>
  <span class="price">$ {{product.price}}</span>
</div>

If you see the browser, now you can drag the individual product. This is all possible due to the attributeBindings: ['draggable'] property at app/views/product_item.coffee.

If you inspect one of the product, you can see it like <div id="ember261" class="ember-view" draggable="true">....</div>. Out of several Events, HTML5 drag and drop events are:

  • dragStart
  • drag
  • dragEnter
  • dragLeave
  • drop
  • dragEnd

We can trasfer and receive the data using the setData and getData method of HTML5 Drag and Drop API.

Now, lets introduce the Cart view where the user can drop the products.

app/views/cart.coffee
1
2
3
4
5
6
7
8
9
module.exports = App.CartView = Ember.View.extend
  templateName: 'cart'
  classNames: ['basket']
  dragOver: (ev) ->
    ev.preventDefault()
  drop: (ev) ->
    id = ev.dataTransfer.getData('text/data')
    record = @get('controller').findProperty('id', Number(id))
    console.log record

And this is the template.

app/templates/cart.hbs
1
2
3
<div class="shop_cart">
  <span>Drop the product here</span>
</div>

Now, if the product is dragged and dropped on the basket, the dragged product should be logged into the console. The method getData on ev.dataTransfer object can retrieve the data. In this case, we get the product id of the product. Since we get the id of the product, we can get the product using the findProperty method.

In the next part, we’ll add more functionality to this app such as:

  • Update the Total cart price
  • List the products added in the cart

The code is pushed at https://github.com/millisami/drag-n-drop-emberjs

Update: Feb 22, 2014 Part 2 is released at Drag N Drop With Emberjs, Part 2

To stay updated, just follow @nepalonrails

Rapid Emberjs App Development Workflow

In recent few months, I am learning and developing Emberjs apps. There are so many ways to setup an Ember app. Instead of the Ember internals and how-tos, here I like to post about the development workflow and tooling around it. Since I am a Rails dev, my first attempt was obviously to go with it. There are 2 rubygems, as of this writing, that sets up the ember with rails. First is the ember-rails which integrates with Asset pipeline. It provide the generators to install the latest releases of emberjs. This gem generates the folder structure inside the app/assets/javascripts folder and also builds with development or production variants of emberjs according to environment.

Another gem is the Ember Appkit Rails. It completely removes app/assets/javascripts from the asset loadpath and puts the app/ and config/ directories in your Rails application to the asset pipeline. In order for the resolver to work properly Ember application files need to go into the correct directories. For example, models must go into app/models, controllers must go into app/controllers, routes must go into app/routes You must use es6 modules in your application files. ember-appkit-rails handles the transpiling for you via the es6_module_transpiler-rails gem as long as you add the .es6 extension to the end of the file.

Any application will require a backed/API to hold the data, so does Ember. So, building out with Rails, one feels better to develop the API along the Ember app inside Rails. I did feel better too.

And the question arise, what about the Tests. Well, emberjs itself has its own package called ember-testing for integration testing. Its written using javascript testing framework called Qunit. Then another question pops up, how do I set up these libraries. After some interwebs search, I found this project called Teaspoon. It is a Javascript test runner built on top of Rails – use Jasmine, Mocha or QUnit in the browser or headlessly using PhantomJS or with Selenium Webdriver. It gives commands like rake teaspoon or bundle exec teaspoon to run the js tests.

Few days later, after running these Rake tasks and Rails commands, I started to feel uncomfortable. When the app grew bigger, those commands started to take longer time and the feeling: Why am I dependent in Ruby and Rails for the pure JS app? Then my quest for other kinds of setup and development flow started.

Pretty much I hope, many of us have come around the Ember Starter Kit project. Its a Grunt based project and has various features. Grunt is a general purpose Javascript task runner. Its entire architecture is based upon the Plugin system. When my app started to evolve little bigger, file numbers increased, the same feeling of slow-ness started to come up when it tries to compile those files. When I change and save a single file, its compilation started to take few seconds.

My simple requirements:

  • No dependency on Ruby
  • Faster compilation
  • Organized/Structured code/folder
  • Coffee-script support
  • Faster test runner/feedback
  • Environments in the JS framework

The above development framework or setup lack at least one of my requirements. So, my quest didn’t stop here and continued on. Then I found this project Tapas with Ember. It is a Brunch skeleton for rapid Emberjs app development. It is an ultra-fast HTML5 build tool. But first, a basic look upon Brunch.

Straight from its homepage:

Brunch…

  • compiles your scripts, templates, styles and lints them
  • wraps the scripts and templates in common.js / AMD modules,
  • concatenates scripts and styles
  • generates source maps for concatenated files
  • copies assets and static files
  • shrinks the output by minifying code and optimizing images
  • watches your files for changes, notifies you about errors via console and system notifications

Install Brunch

npm install brunch
npm install coffee

Tapas with Ember comes with various built-in features:

brunch new gh:mutewinter/tapas-with-ember <appname>
cd <appname>
cake server

Open http://localhost:3333 and check out your brand new Ember app! Code changes you make will be automatically re-loaded in the browser. Edit app/routes/index.coffee to see live-updating in action. Tapas with Ember runs Ember 1.3.1 out of the box. You can update to Beta or Canary builds using the commands below. It’s also easy to install the latest Ember Data or Ember Model using the cake scripts written in Cakefile.

cake ember:install
# cake -t "v1.3.1" ember:install # for v1.3.1 tagged release
# cake -c "beta" ember:install # for beta
# cake -c "canary" ember:install # for canary

cake ember-data:install
# cake -t "v1.0.0-beta.4" ember-data:install # for v1.0.0-beta.4 tagged release
# cake -c "canary" ember-data:install # for canary

As the test runner, it uses Testem which is faster.

And there are lots of features built for which you can look at its page Tapas with Ember

So, for now I’ve settled up with Brunch and its Tapas for Ember skeleton for my rapid development workflow. Also there are tweets around asking for Ember App kit to use Brunch instead of Grunt. I would like to know your workflow or views on Ember app development. Just drop them in the comments below.

Using Rails Route Helpers Inside Engine

In a Rails app, we can access the route helpers calling methods on Rails.application.routes.url_helpers or by including the module include Rails.application.routes.url_helpers

But inside an engine, it will not work. For this we’ve to use the engine’s url_helpers module.

1
MyApp::Engine.routes.url_helpers.new_post_path

Assuming that the engine have a post resource.

Octopress Heroku Custom Domain to Redirect to Non-www

Recently I’ve moved to Octopress with Heroku free hosting. Here I am not going to on how to migrate or create a new Octopress powered blog. Instead polish the final DNS part.

Objective: Visiting to www.nepalonrails.com or www.nepalonrails.com/any-page, should do 301 permanent redirect to nepalonrails.com or nepalonrails.com/any-page, carrying along the PATH_INFO as well.

After all the work done, open up the Heroku’s app dashboard and add the custom domain.

heroku custom domain

For this blog, I’ve only added the root domain nepalonrails.com

Then on your DNS provider, we have to add the CNAME records. Here I use NameCheap. In the manage domain page of NameCheap, click the All Hosts link in the left sidebar and add those values:

namecheap domain manage

Setting Up Rails Engine With Rspec, Guard and Zeus

Update: One gain, you don’t have to cd into the spec/dummy folder. Just run from the same engine’s root files.

I love zeus for testing rails apps because of its speed. Recently I have re-started developing an engine and the default zeus start command is not enough for a rails engine.

So, found this gist and I could setup to run it. Here is the my copy of that gist. Do rename the my_engine with your engine name at line 8.

engine_plan.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
require 'zeus/rails'

ROOT_PATH = File.expand_path(Dir.pwd)
ENV_PATH  = File.expand_path('spec/dummy/config/environment',  ROOT_PATH)
BOOT_PATH = File.expand_path('spec/dummy/config/boot',  ROOT_PATH)
APP_PATH  = File.expand_path('spec/dummy/config/application',  ROOT_PATH)
ENGINE_ROOT = File.expand_path(Dir.pwd)
ENGINE_PATH = File.expand_path('lib/my_engine/engine', ENGINE_ROOT)

class EnginePlan < Zeus::Rails
end

Zeus.plan = EnginePlan.new

And now we need the zeus.json file as well.

zeus.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
  "command": "ruby -rubygems -r./engine_plan -eZeus.go",

  "plan": {
    "boot": {
      "default_bundle": {
        "development_environment": {
          "prerake": {"rake": []},
          "runner": ["r"],
          "console": ["c"],
          "server": ["s"],
          "generate": ["g"],
          "destroy": ["d"],
          "dbconsole": []
        },
        "test_environment": {
          "test_helper": {"test": ["rspec", "testrb"]}
        }
      }
    }
  }
}

With this setup, now lets run the specs. Install zeus with gem i zeus. In one window, start zeus with zeus start and in another window run the specs zeus rspec spec/file_spec.rb

If your spec pass, you might notice it will run it twice, upper one being green and another failing one. To mitigate this issue, in the spec_helper.rb file, just delete/comment the line require rspec/autorun.

Ahaa!! moment!! Wait, everytime I write/modify the code, I’ve to go to the terminal and run that command zeus rspec spec/file_spec.rb again and again.

You might be yelling, dude we have guard for this. Yeah!! Yeah!! Recently, guard-rspec has added the support for zeus, so lets install it first. Put it in the Gemfile and bundle it.

Gemfile
1
2
3
4
5
group :development do
  gem "guard"
  gem "guard-rspec", require: false
  gem "zeus", require: false
end

Then init the Guardfile

Guardfile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
guard :rspec, cmd: 'zeus rspec', keep_failed: true, all_after_pass: true do
  watch(%r{^spec/.+_spec\.rb$})
  watch(%r{^lib/(.+)\.rb$})     { |m| "spec/lib/#{m[1]}_spec.rb" }
  watch('spec/spec_helper.rb')  { "spec" }

  # Rails example
  watch(%r{^app/(.+)\.rb$})                           { |m| "spec/#{m[1]}_spec.rb" }
  # watch(%r{^app/(.*)(\.erb|\.haml|\.slim)$})          { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
  watch(%r{^app/controllers/(.+)_(controller)\.rb$})  { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
  watch(%r{^spec/support/(.+)\.rb$})                  { "spec" }
  watch('config/routes.rb')                           { "spec/routing" }
  watch('app/controllers/application_controller.rb')  { "spec/controllers" }

#   # Capybara features specs
#   watch(%r{^app/views/(.+)/.*\.(erb|haml|slim)$})     { |m| "spec/features/#{m[1]}_spec.rb" }
end

Now you can run guard either with the bundle exec prefix or just the guard command if you have installed Guard outside the bundle with gem i guard

Happy Engine Testing!

Publishing Cookbook to Chef Community Site

After creating my first errbit cookbook, and publishing it on the chef community site, I’d to do some stretches to publish it.

First, you need to tgz your cookbook and it should have the metadata.json file otherwise the validation fails and the cookbook won’t be published.

So, I am putting it here for me and others:

In your cookbook dir, create a dir .chef with a knife.rb file in it with the following line:

cookbook_path "."

Then issue the command knife cookbook metadata . (Don’t forget the dot) This will generate metadata.json file.

Better to commit it here and push the changes to your git repo.

Now step out 1 dir path from your cookbook folder and do the compressing.

cd ..
tar -czf errbit.tgz --exclude bin --exclude .envrc --exclude .vagrant --exclude .bundle errbit

You might have to change/add the --exclude vars according to your setup.

Now we’ve the errbit.tgz file with the metadata.json file in it which you can upload to the community site at http://community.opscode.com/cookbooks/ne w

When updating the cookbook later, do change the version in metadata.rb file and repeat the same process to publish your cookbook’s changes.