Ask Awesomely

Build Typeforms awesomely. In Ruby.

Gem Version Build Status

Table of Contents

Installation

I wouldn't recommend you do this yet, because it doesn't actually work. Nevertheless, add this line to your application's Gemfile:

gem 'ask_awesomely'

And then execute:

bundle

Or install it yourself as:

gem install ask_awesomely

Usage

Authentication

Firstly, you will need to be able to authenticate:

AskAwesomely.configure do |config|
  config.typeform_api_key = ENV["YOUR_TYPEFORM_IO_API_KEY"]
end

Your API Keys are super secret so don't commit them in your code. Use ENV or something like dotenv so you can keep the credentials out of the repository. This stops bad people from stealing the key and hijacking your Typeform I/O account.

If you're using images

It's possible to create questions that have images (or pictures, as we call them) attached. In fact, one field type relies on this!

Currently Typeform I/O is only able to accept a URL to an image, which means that any images you use have to be uploaded elsewhere first.

If you already handle image uploads in your app (for example, with Dragonfly), you're okay.

If you don't, you will need to give AskAwesomely your AWS credentials so it can do all of the heavy lifting for you.

AskAwesomely.configure do |config|
  config.aws_access_key_id = ENV["YOUR_AWS_ACCESS_KEY_ID"]
  config.aws_access_key_secret = ENV["YOUR_AWS_ACCESS_KEY_SECRET"]
end

As before, don't commit these keys to your repo unless you want bad things to happen. Check up on the AWS Best Practices if you want to know more.

Basic example

You will want to create a class that represents a specific form to be built:

class MyNewTypeform

  include AskAwesomely::DSL

  title "My New Typeform"

  tags "awesome", "hehe"

  field :statement do
    say "Hello, Rubyists!"
  end

  field :multiple_choice do
    ask "What is your favourite language?"
    choice "Ruby"
    choice "Python"
    choice "Javascript"
    choice "COBOL"

    can_specify_other
  end

end

After that, it's simply a matter of calling build on the class:

typeform = MyNewTypeform.build

Check the rest of the (not currently finished) documentation to find out what else you can do.

Check out Typeform I/O for detailed information about the API, and how to get your API key.

Available fields and options

Each field has unique properties. Here are the fields you can use, and the extra things you can do to customise them.

Note that some options might not yet be available on Typeform I/O.

Also note that some field types and customisations that are available on Typeform.com may not be available on Typeform I/O.

Statement

A block of text that isn't a question and requires no answer.

field :statement do
  say "what you want to say"
  button_text "Okay, next question"
  show_quotation_marks
end

Short text

A question where the answer is a short amount of free-form text.

field :short_text do
  ask "What do you think of me?"
  max_characters 3
end

Long text

A question where the answer is free-form, like short_text, but can be much longer.

field :long_text do
  ask "What do you *really* think of me?"
  max_characters 700
end

Multiple choice

A question that allows the user to choose from a range answers.

field :multiple_choice do
  ask "Why not both?"

  choice "Yes"
  choice "No"

  allow_multiple_selections
  randomize
end

Picture choice

Similar to multiple_choice, only you can add a picture to each answer too. This will handle the complications around image uploading for you if you're dealing with local files and pass along your AWS credentials. Otherwise, it will work with whatever system you already have in place – just give it a URL instead of a file path.

field :picture_choice do
  ask "Which of these is a spoon?"

  # `image` can be a `String`, a `URL`, a `Pathname`, or a `File`
  choice "Knife", picture: "http://iseeyouveplayedknifeyspooneybefore.com/spoon.jpg"
  choice "Spoon", picture: Rails.root.join("app/assets/images/knife.jpg")
  choice "Spork", picture: "/var/www/images/spork.png"

  allow_multiple_selections
  randomize
end

Similar again to multiple_choice, when you have too many options to show at once.

field :dropdown do
  ask "Which is the odd one out?"


  (1..100).each do |number|
    choice (number != 70 ? number : "seventy")
  end

  in_alphabetical_order
end

Yes/No

A question that demands the user to commit to their own certainty.

field :yes_no do
  ask "Will you marry me?"
  required
end

Number

A short_text style question that only accepts numerical input. It can be limited to a range.

field :number do
  ask "How many fingers am I holding up?"

  min 0
  max 4

  # alternatively
  between 0..4
end

Rating

A question that prompts the user to quantify their opinion of something.

field :rating do
  ask "How much did you enjoy Jonny Wiseau's seminal hit, The Room?"

  steps 10
  shape :thumbs_up
end

Opinion Scale

A refined form of rating more appropriate for "bad / neutral / good" style questions.

field :opinion_scale do
  ask "How would you rate our service?"

  steps 11

  left_side "Terrible"
  middle "Average"
  right_side "Amazeballs"

  starts_from_one
end

Email

A question type painstakingly created to request a valid email address.

field :email do
  ask "Can I have your email please?"
  description "So you can be my best pen-pal buddy forever."
end

Website

Ask the user to enter a valid URL.

field :website do
  ask "Show me a funny GIF"
end

YAAAAWWWWN

Like the yes_no field, but primarily intended for accepting terms and conditions. Stuff like that.

field :legal
  ask "Do you accept my lofty demands?"
  required
end

Common Customisations

Every field type allows you customize the following things:

  • the description: a smaller chunk of text to give extra detail to a question
  • tags: small strings to help you identify questions
  • answer required: prevent form submission until the question is answered
field :legal do
  # ...
  description "Don't accept, I dare you."
  required
  tags "some-kind-of-tag-for-legal", "wtf"
end

Passing Context

note: not yet supported

Building a form full of hard-coded data is all well and good, but it doesn't offer much benefit over using a web interface. What if you want to build personalised forms based on, say, an ActiveRecord model?

Lets create the basic form, with a title and a single question:

class UserTypeform
  include AskAwesomely::DSL

  title -> (user) { "#{user.name}'s New Typeform" }

  field :yes_no do
    say -> (user) { "Is this your email address? #{user.email}" }
    required
  end
end

Notice that we're now using a lambda for the title and question, instead of a hardcoded string. In this case, we're expecting an object that has a name and an email, so we can inject that data into the form.

The next step is to build the form with such an object. For example, in Rails:

rodrigo = User.create(name: "Rodrigo", email: "[email protected]")

typeform = UserTypeform.build(rodrigo)

Or in plain Ruby:

gabriela = OpenStruct.new(name: "Gabriela", email: "[email protected]")

typeform = UserTypeform.build(gabriela)

Rendering the Typeform

Calling build will send your Typeform structure to the API right away, and if everything is hunky-dory you'll get a nice new Typeform object to play with.

Getting the URL

Every Typeform you successfully generate through Typeform I/O will come back with a new public URL. This points to the rendered version of the Typeform and it's what you can send out to your users, or participants, or whomever.

For example, you might email a bunch of personalised Typeforms in a Rails app like this:


User.find_each do |user|
  typeform = UserTypeform.build(user)
  TypeformMailer.send_to_user(user, typeform.public_url)
end

Embedding

You can also embed a form straight away if you prefer. AskAwesomely generates the correct embed code for you, with the correct URL and Typeform title. The style can be customised with CSS but some aspects of the embed itself are not currently customisable (e.g. changing button text and widget size).

To see what each embedding option looks like, check out the Embedding Modes[http://docs.typeform.io/docs/embedding-introduction) documentation at Typeform I/O. It has pictures and everything.

Assuming you have built a Typeform as in the other examples, rendering the embed code is simple:

Pops up over the page content and fills most of the screen.

typeform.embed_as(:modal)

Widget

Allows you more control over where the form is embedded and how it appears. Just a box on the page.

typeform.embed_as(:widget)

Drawer

Makes the form slide in from the side of the page, hamburger menu style, and fills at least half of the screen.

typeform.embed_as(:drawer)

Fullscreen

Becomes the entire page.

Note that this outputs a complete HTML document, CSS and all. If you're working with your own views and layouts this will not embed properly unless inserted into an empty layout. Can work well with Sinatra or other small frameworks if you just want to build a form and display it.

typeform.embed_as(:fullscreen)

Todo

  • implement and test dynamic fields
  • test the API interaction behaves well
  • deal with errors from the API
  • allow webhook URL to be configured
  • allow design to be configured

Development

After checking out the repo, run bin/setup to install dependencies. Then, run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release to create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

  1. Fork it (https://github.com/leemachin/ask_awesomely/fork)
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request