Rails: Compare multiple attributes with one assertion

Often times in Rails I will want to test that a model has the correct attributes after a method has ran. One way to do this is to have an assert for each attribute such as:

  test "should create a correct post" do
    post = PostGenerator.run
    assert_equal "Title", post.title
    assert_equal "Body", post.body
    assert_equal "Posted", post.status
  end

This can get even uglier if you have a lot of things you want to verify. Here is a trick to verify all of those things on one line:

  test "should create a correct post" do
    post = PostGenerator.run
    expected = {title: 'Title', body: 'Body', status: 'Posted'}
    assert_equal expected, post.attributes.symbolize_keys.slice(*expected.keys)
  end

Cheers!

,

Leave a comment

The Yin and Yang of product and marketing

Product is what is most important (Yin)

Opinion #1: All that matters is that you have a great product. If you have a great product people will naturally tell their friends and your product will go viral and then you won’t have to worry about marketing. If you build it, they will come.

Marketing, Sales, and Traction is the only thing that matters (Yang)

Opinion #2: I would take a product that needs improvement, but that has thousands of eye balls, over a great product that doesn’t have any traction. The most important thing that you need is traction, a great product can come later!

Q. Who is right?
A. They both are!

Both are important, both should not be left undone. My opinion is you should spend about half of your time/resources on building a wonderful product and the other half on building traction.

You will encounter people in both camps. You will see CEO’s who spend all of their time and energy building features and widgets and very little time building traction for their products. You will see those that only focus on building hype and buzz for a half baked product.

How are you spending your time and resources? I try to keep a tab on how much time I spend on each and try to keep them closely balanced.

Remember the Ying and Yang of product and marketing!

2 Comments

Make up what your App lacks with great customer support

First Launch

We have all been there, you have just launched your first mobile or web app and you have a laundry list of 200 features that need added. You almost feel a little embarrassed with your app because of its lack of features and polish. You think that you will get inundated with emails of people being highly offended that your app has bugs or doesn’t have the feature that they need.

When you are first starting out, this is normal and natural. Even large companies start out with products that have a limited feature set, including Dropbox, the first iPhone, Basecamp, and many others.

TrackMyDrive

My first version of TrackMyDrive had a very limited feature set. In-fact the only thing the smart phone app would do is allow you to start GPS tracking and stop GPS tracking. It didn’t have half of the features that it has now. As you would expect, I would get a lot of customer service emails requesting features, all of which I responded to in a timely and friendly manner.

An aha moment

I was once emailed about a small bug in TrackMyDrive, I responded within minutes, took the time to understand the problem and had it fixed the same day. I interacted with the customer every step of the way, and what was the response? The customer was THRILLED!!  Wait, what? Shouldn’t the customer be pissed that the bug happened in the first place?

Because I took the time and made the customer feel important, it turned to be a win. In fact, the customer gave me a five star review and she shared the experience of how great the customer service was!

Do what the “big guys” cannot

In the beginning you are at a disadvantage. You will  have less features, users, traction, money, and word of mouth than your competitors. However, you can use these to your advantage. You can turn your disadvantages into your advantages. Here is what you can offer, that they cannot:

1. A personal experience
When you have 100,000 users, it is much more difficult to offer a personalized experience to all of your users. However, when you have 10 users, you can.

2. A feeling that they are part of the team.
Send your early customers lots of emails, and communicate with them often. They can start to feel like they are “part of the team”. Do you have a mockup of a new design? Send it their way. Thinking of implementing different pricing? Ask for their opinion. They will begin to get the feeling of ownership and responsibility and will be much more willing to overlook your faults.

3. Simplicity
Your App not having every feature is an advantage. Users like simple apps that solve simple problems. The world is filled with too many Apps trying to do too much. Your App’s advantage is that the interface is simple and does one thing well.

Conclusion

Don’t be down in the dumps when you are starting out! In all reality your App has a long, long way to go! However, that is okay, you can make up what your App lacks by offering great customer support.

Leave a comment

Always Acknowledge the Customer!

We have all been there. You walk into a business or store and see an employee at the counter. Unfortunately, however, the member of staff doesn’t look up and greet you; seemingly they are too busy doing something else. “Surely they must have heard me come in, they even have one of those stupid bells on the door… and I am five feet from them,” you think to yourself.

But the employee continues to ignore you and goes into the back office.

“Oh crap! Where are they going?” you wonder. “When are they going to come back? Am I going to be standing here for the next five minutes? Should I say something? Am I even at the right desk?”

Chances are, the employee isn’t deliberately trying to make you to feel unwelcome; perhaps they are simply counting the cash from a previous sale and filing the receipt in the back office. They have probably acknowledged your presence in their mind and they will be right back.

But is it really that hard to say: “Hello Sir, I will be right with you?”

ALWAYS, ALWAYS, ALWAYS acknowledge the customer!

This rule also applies to your email correspondence. If you don’t have time to write a detailed answer to a customer’s email, simply tell them you are not in the office, but that you will get back to them later in the day. It will take you two minutes to write a response of this nature and through sending a quick note you will let your customer know you are aware of them (and their needs).

Don’t forget, if you tell a customer you will do something, then make dang sure you do it. For example, if you inform a client that you will respond to their email within a few hours, make every effort to contact them before the end of the day, regardless of whether you have the answer to their question or not. It is better to say, “Hey, something came up, I haven’t forgotten about you, and should have an answer to your question soon” than to not send them an email at all.

Remember, it is your duty as the business owner to follow up with the customer—not the other way around. I cringe when I have to send reminder emails to a sales person who had previously told me they would get back to me (and never did).

Always acknowledge the customer and always follow up when you say you will. If your customers are asking for status updates on their queries or correspondence, you are doing it wrong.

,

1 Comment

RubyMotion gem tutorial – part 2

In our previous tutorial (part 1) I showed you how to get started developing your first RubyMotion gem.

In this post, we will cover adding some niceties to your gem including:

  1. Rake tasks
  2. Bundler
  3. Running in the simulator
  4. Dependencies
  5. Specs

These will make developing our gem easier. This tutorial will build on the code written in the previous post. Your directory structure should be:

atm.gemspec
lib/
  atm.rb
  atm/
    deposit.rb

Rake tasks
Creating a Rakefile allows you to run custom tasks. Here we have created a task called “random_task”

$:.unshift("/Library/RubyMotion/lib")
require 'motion/project'

Motion::Project::App.setup do |app|
end

task :random_task do
  puts "Hello Random Task!"
end

Run it:

$ rake random_task
-> Hello Random Task!

Adding Bundler
Because we are planning on running this in the simulator(and including dependencies), we will add Bundler to our gem.

Create a file called Gemfile. Insert the following text:

source 'https://rubygems.org'

gem 'rake'

You can now run the previous rake task using bundle exec

$ bundle exec rake random_task
-> Hello Random Task!

Running in the simulator
Running your gem in the simulator will allow you to test it without having to include it in a separate project.

You will need an app directory and an app_delegate.rb file. Your directory structure should now be

atm.gemspec
Rakefile
Gemfile
app/
  app_delegate.rb
lib/
  atm.rb
  atm/
    deposit.rb

We need to require our lib folder in our Rakefile so we can use our own library in the simulator. Our Rakefile should now look like this

$:.unshift("/Library/RubyMotion/lib")
require 'motion/project'

$:.unshift("./lib/")
require './lib/atm'

Motion::Project::App.setup do |app|
end

task :random_task do
  puts "Hello Random Task!"
end

Place this code into your app_delegate.rb file

class AppDelegate
  def application(application, didFinishLaunchingWithOptions:launchOptions)
    @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
    ATM::Deposit.create

    true
  end
end

To start the simulator you can simply run:

$ bundle exec rake

Adding Dependencies
When creating gems, it is likely you will want to use other gems to aid your development.
A common RubyMotion gem is bubblewrap, let’s add it as a dependency so we can use it in our gem

# -*- encoding: utf-8 -*-
Gem::Specification.new do |s|
  s.name        = "atm"
  s.version     = '0.0.1'
  s.summary     = "Sample gem"
  s.description = "Sample gem"
  s.authors     = ["Steve Books"]
  s.add_dependency "bubble-wrap", "1.1.4"
end

This tells any app using this gem that bubble-wrap version 1.1.4 will be required. We will also need to add bubblewrap to the Gemfile so we can use it in our own simulator.

source 'https://rubygems.org'

gem 'rake'
gem 'bubble-wrap', '1.1.4'

After modifying the Gemfile run bundler:

$ bundle install

Modify the Rakefile to include bundler and bubblewrap. This is required for us to run it in the simulator:

$:.unshift("/Library/RubyMotion/lib")
require 'motion/project'
require 'bundler'
require 'bubble-wrap'

$:.unshift("./lib/")
require './lib/atm'

Motion::Project::App.setup do |app|
end

task :random_task do
  puts "Hello Random Task!"
end

To verify this works, we will modify our deposit.rb class to use a Bubblewrap utility

module ATM
  class Deposit
    def self.create
      puts "Screen Width:#{Device.screen.width}" #bubblewrap
      puts "Creating a deposit!"
      true
    end
  end
end

$ bundle exec rake
-> Screen Width:320.0
-> Creating a deposit!

Specs
Rather than testing all of your changes using the simulator, you can create specs that can be run for your gem. This allows you to developer faster and test our gem.

Create a spec directory (from the base of your gem) and a deposit_spec.rb file

describe "Deposits" do
  it "should create" do
    ATM::Deposit.create.should == true  
  end
end

Your directory structure should now be:

atm.gemspec
Rakefile
Gemfile
app/
  app_delegate.rb
lib/
  atm.rb
  atm/
    deposit.rb
spec/
  deposit_spec.rb

Create a spec task in Rakefile:

$:.unshift("/Library/RubyMotion/lib")
require 'motion/project'
require 'bundler'
require 'bubble-wrap'

$:.unshift("./lib/")
require './lib/atm'

Motion::Project::App.setup do |app|
end

task :random_task do
  puts "Hello Random Task!"
end

task :spec do
  App.config.spec_mode = true
  spec_files = App.config.spec_files
  App.config.instance_variable_set("@spec_files", spec_files)
  Rake::Task["simulator"].invoke
end

Run your specs:

$ bundle exec rake spec

Creating a gem is not intimidating. Moving code into gems keeps your project clean and helps others in the community. Happy gem cutting!

Github: Source Code

Leave a comment

RubyMotion gem tutorial

RubyMotion makes developing iOS much easier. Writing RubyGems will allow you to share your code with other developers. However, if you have never authored a gem, it can be a bit intimidating. I will walk you through how to create your first gem. We will call it “ATM”

1. Create the following file tree

atm.gemspec
lib/
  atm.rb
  atm/
    deposit.rb
  

2. Modify the file lib/atm.rb with the following code

unless defined?(Motion::Project::Config)
  raise "This file must be required within a RubyMotion project Rakefile."
end

Motion::Project::App.setup do |app|
  Dir.glob(File.join(File.dirname(__FILE__), 'atm/*.rb')).each do |file|
    app.files.unshift(file)
  end
end

3. Modify the file lib/atm/deposit.rb with the following code

module ATM
  class Deposit
    def self.create
      puts "Creating a deposit!"
    end
  end
end

4. Modify the file atm.gemspec with the following code

# -*- encoding: utf-8 -*-
Gem::Specification.new do |s|
  s.name        = "atm"
  s.version     = '0.0.1'
  s.summary     = "Sample gem"
  s.description = "Sample gem"
  s.authors     = ["Your name"]
end

5. Create a github repository and upload your code (will not cover this in this tutorial)

6. Include your gem in a RubyMotion project

Gemfile:

  gem 'atm', '0.0.1', :git => 'git://github.com/stevebooks/rubymotion-gem-tutorial.git' #replace this with yours

Rakefile:

require 'atm'

AppDelegate:

def application(application, didFinishLaunchingWithOptions:launchOptions)
  ATM::Deposit.create
  true
end

7. Your done! See that wasn’t that hard!

Github: Source Code

3 Comments

Follow

Get every new post delivered to your Inbox.

Join 25 other followers