Skip to main content

Mobomo webinars-now on demand! | learn more.

There's been a lot of controversy surrounding the changes to Rails 3.1. It started with an epic GitHub commit thread and the discussion exploded again in the past few days after What the Hell is Hapenning to Rails and Yehuda's response thereto. I'm going to address the issue from a perspective that honestly hadn't even occurred to me until I just said it while in a conversation with some Kansas City Ruby folks after the last meetup: "What if Rails isn't for beginners anymore?"

Rails gained its popularity on the strength of its simplicity. The 15-minute blog was a shockingly powerful demonstration of what the framework could do, and from there it has gained thousands upon thousands of dedicated developers. But that's just the thing: now it has thousands of dedicated developers. And these developers are building some of the most powerful and advanced web apps anywhere on the internet. It's only natural that as the needs of the community grow so too does the framework. What we may be seeing is a point where Rails is becoming the tool for Ruby web experts instead of Ruby web novices. But if that's true, is it necessarily a bad thing?

I built RailsWizard as part of the Rails Rumble last year and I thought it would be a tool that would serve two purposes: help me quickly spin up new apps I'm working on and also serve as a step-by-step guide for novice developers who need to get started building a Rails app. However, two rewrites later RailsWizard is a tool that is incredibly fast for my purposes but almost incomprehensible to anyone who doesn't know what they're doing. The tool evolved to focus on power for experts rather than friendliness for novices. Ultimately that's the decision that has to be made for any tool or website: how much tradeoff are you going to give between making something easy to pick up and efficient for experts?

Since my livelihood depends on being able to rapidly build advanced web applications using Rails, you won't see me beating the drum to take away power from Rails for the sake of novice ease-of-use. In fact, I'm beginning to wonder if Rails is the wrong place to get people started with Ruby web development anyway. There's always been the problem of people who are Rails but not Ruby developers because ActiveSupport and the facilities Rails give you can make it hard to know what's stdlib and what isn't. If people learned Sinatra first, or if the community rallied around a "slightly more than Sinatra" framework like Padrino for newcomers and built up the requisite tutorials and documentations for 15-minute blogs and other things, then the novices who cut their teeth on those tools can come to Rails when they actually understand the power that Rails gives them as developers. They will understand Rails better because they have begun to stretch the limits of the lightweight frameworks and they need more. Maybe a system like that would make for better Ruby and Rails developers.

I'm not saying that any of this is necessarily true, but I think it's another facet of the debate that hasn't been explored yet. Personally I love the changes that have been coming to Rails. The asset pipeline may be the most important addition to Rails since even before 3.0: it is a game-changing piece of technology that has been a long time coming. I think the Rails core team has done an incredible job of pushing the envelope and refusing to remain complacent. And I think that's important, probably more important even than beginner friendliness. Because if Rails gets complacent, if the core team stops pushing out into the weird and uncomfortable, then five years from now nobody will be using it because something better will have come along. And I like Rails.

Categories
Author

Before I dive into the launch mode of an activity, we need to first understand the term, 'Task'. A task is the stack ("Last in, First out") which contains a collection of activity instances. Normally, when a user starts an app a new task will be created, and the first activity instance is called as a root of the task. The Android system can hold multiple tasks at the same time and only one task is in the foreground. Similar to a double click of the home key on iOS, if you long press the HOME key on Android you'll be presented with a list of your currently running applications. You can select any one of these applications (which are currently running in the background) in order to bring it to the foreground and interact with the app! Of course, because background tasks do tend to use up your processor cycles you should try to keep your backgrounded apps to a minimum to ensure your phone performs optimally.

Now let's look at the launch mode of an activity. Launch mode allows you to define how a new instance or the existing instance of an activity is associated with the current task. The activity launch mode has four valid values:


The 'standard' is the default value. The four values fall into two groups:

  • 'standard' and 'singleTop' can instantiate multiple activity instances and the instance will stay in the same task.
  • For 'singleTask' or 'singleInstance', the activity class uses the singleton pattern, and that instance will be the root activity of a new task. Let's examine each value:

"standard":

Multiple instances of the activity class can be instantiated and multiple instances can be added to the same task or different tasks. This is the common mode for most of the activities.

"singleTop":

The difference from 'standard' is, if an instance of activity already exists at the top of the current task and system routes intent to this activity, no new instance will be created because it will fire off an onNewIntent() method instead of creating a new object. Let's take the Twitter-oauth integration as example. Suppose we have the following NewsDetailActivity declared:
And in the activity we will have the following code to start the oAuth process which will bring up the browser to visit Twitter's authorization page:


So if a user goes to this activity in the current task (let's say Task #1), a new instance of NewsDetailActivity will be pushed to the top. Now start the oAuth process and the Android system routes the intent to the default Android Browser application, whose launch mode is 'singleTask'; that means a new Task begins for the browser activity, let's say Task #2. Hence the 'NewDetailActivity' is still on top of the Task #1.

After the user finishes the authorization on Twitter's page, the customized callback url 'oauth://twitter' will be invoked. Because NewsDetailActivity declares support for that data type, the system routes the intent to the 'NewsDetailActivity'. Since NewsDetailActivity's launch mode is 'singleTop', and the top instance on Task #1 will be reused, its onNewIntent() method will be invoked to continue oAuth's last step. Here is the code for that:

"singleTask":

A new task will always be created and a new instance will be pushed to the task as the root one. However, if any activity instance exists in any tasks, the system routes the intent to that activity instance through the onNewIntent() method call. In this mode, activity instances can be pushed to the same task. And if the user clicks the BACK key from the singleTask activity, the system will return the user to the previous activity.

This mode is useful for activities that act as the entry points. For example, in a tab-based Twitter client, we can declare the main TabActivity as singleTask. This is also useful if you only want a single instance of the activity to be created. One example of singleTask is the Browser application. Let's take a Twitter-client-application as example, where the main activity is a TabActivity and has three tabs: tweets, replies and messages. And we want to suppose auto-refresh and notification function when app is running.

In AndroidManifest.xml, we have:

Suppose we have the notification for new tweet/replies/messages, and we hope that clickong on the notification will take the user to the current TabActivity, and switch to corresponding tabs. (Here we suppose the app is not closed before user clicks the notification). Because the MainTabActivity's launch mode is singleTask, system routes the intent to the MainTabActivity by calling its onNewIntent() method. And in this method, we can determine which tab to switch to according to the bundle data in the intent.

"singleInstance":

Same as 'singleTask', except that the no activities instance can be pushed into the same task of the singleInstance's. That means, the activity with launch mode is always in a single activity instance task. This is a very specialized mode and should only be used in the applications that are implemented entirely as one activity.

Summary:

Understanding the launch mode will help you design better navigation and implement some special cases. Here we only discuss the launch mode from the AndroidManifest file. Android launch mode can also be declared using the Intent flags, such as FLAG_ACTIVITY_NEW_TASK, FLAG_ACTIVITY_CLEAR_TOP and FLAG_ACTIVITY_SINGLE_TOP. And we will create more posts to talking about intent flags in the near future, so stay tuned!

Categories
Author

Last year, we told you a bit about Intridea's experience with founding the DC Ruby Users Group, and shared some tips for organizing a group of your own. For many developers, and a lot of our remote Intrideans, being in a smaller area doesn't mean you can't get involved.

Introducing the "Hallway Track" Ruby User Group

If founding a Ruby User Group sounds impractical — think again! From my own personal experience, one of the best reasons to travel to regional conferences is not necessarily the talks (though they are certainly phenomenal), but rather, the "hallway track". With the Eau Claire Ruby User Group, there are many similarities:

  1. Hacking on Projects: Put enough monkeys in a room — they'll eventually write Shakespeare. Put enough Ruby developers in a room — well, you end up with the Rails Rumble. Even if everyone comes into a group with their own project in mind, the ability to shoot ideas off of each other, and even pair program, can be just as fulfilling as a great talk.
  2. Learning a New Skill: ECRuby has fairly relaxed meetings, but on occasion we do have folks present; often on a topic asked for at the last meeting. Low-key talks don't need to be as formal. Toss out the slides and take us through an example of how to set up a VPS, or show us some handy tricks with VIM. The laid-back meeting style puts less pressure on the speaker and guarantees we always have material.
  3. Comparing Toolchains: Having the opportunity to meet up with other developers allows you to see just what tools they're working with in their own projects. Often at ECRuby, we may discover a gem or library that we hadn't considered using but fits perfectly within our own project.
  4. Socializing: Finally, developers (especially Ruby developers) are an interesting breed. It never hurts to meet others of our own kind.

The key to a hallway track user group is not bringing in speakers and maintaining a formal environment, but rather, creating a space where developers enjoy picking up new snippets of information, and have the opportunity to learn and grow naturally from each other.

Here are a few tips from our experience with ECRuby:

  • Make the meetings worthwhile for all sizes. At a few of the ECRuby meetings when we were first getting started, our attendance was around 3-4 developers. On the flip side, we've had several meetings where we've had nearly 30. The key, however, is that both of those extremes can be worthwhile meetings. While you want to try and get a feel for attendance for logistical planning, don't simply give up on a group if you've got small attendance. A few folks coding can be just as happy.
  • Consider alternative venues. Because hallway-track group meetings are less formal, it hardly needs to be in a lecture hall. We've been able to give a few ad-hoc demos on a television at a local pub. But with screen-sharing, you may not even need that. Consider bars, coffee shops, even a developer's home — all can make great spots for a meetup.
  • Invest time in recruitment. Semi-annually, ECRuby holds a formal Chippewa Valley Ruby Camp where we offer a free all-day introductory course in Ruby on Rails. The goal is to ensure that 30 new individuals have Ruby on Rails installed, with enough knowledge to experiment on their own time by the end of the day. Usually this brings in several new ECRuby members. Consider any nearby universities or technical colleges that might be ripe with students looking to pick up a new skill.

So whether you're in the heart of Manhattan, or the middle of North Dakota, it's very worthwhile to invest in a Ruby User Group. If there's not one nearby, take a cue from our own Jon Kinney and start up a Green Bay Ruby User Group, or from Daniel Lv and kick off ShanghaiRUG. Not to mention Adam and Renae Bair, who currently run the Maine Ruby User Group. Now get out there and meet some devs!

Categories
Author

One of the first things that anyone has to do in an application is assign instance variables in controllers for use in views, etc. This pattern, while dead simple, has a number of possible implementations that each have their aesthetic benefits and drawbacks. At RailsConf I had the opportunity to hash this out with none other than DHH and David Chelimsky, so I thought it might be a good opportunity to represent the different sides in a post.

The Repeat Yourself Pattern

This is where things start out many times, as they likely should. You're building out your controller for the first time, and you set the instance variable you need in each action:

class WidgetsController < ApplicationController   def show     @widget = Widget.find(params[:id])   end    def edit     @widget = Widget.find(params[:id])   end end 

This method, while very clear, has the obvious problem of being repetetive. What happens when your code isn't as simple as Model.find? You're going to run into trouble quickly. So let's try a few abstractions.

The Getter Pattern (The David Chelimsky Way)

So the simplest abstraction is to do what we normally do when we're repeating ourselves: define a method!

class WidgetsController < ApplicationController   def show     @widget = get_widget   end    def edit     @widget = get_widget   end    private    def get_widget     @widget = Widget.find(params[:id])   end end 

This pattern has some obvious advantages over repetition: it's pretty clear what's happening while giving us the opportunity to define our finder code in a single location. However, we're still duplicating a line at the top of each action which has a very slight smell.

Note: I'm attributing this to David Chelimsky because I heard him talking about it when I entered the conversation not necessarily because he prefers it to other methods.

The Helper Pattern (The Michael Bleigh Way)

So how can we better abstract this? Well, we're going to be accessing this instance variable primarily in the view, so why are we bothering to explicitly set it in the controller? This is the pattern that I have been using for the last couple of years:

class WidgetsController < ApplicationController   def show; end   def edit; end    private    def widget     @widget ||= Widget.find(params[:id])   end   helper_method :widget end 

This gives us a helper that we can call from our controller or our view that will lazily fetch the widget when we need it and not before. Personally I like this pattern quite a bit: I think it's relatively clear and works well in the various ways I've used it. However:

  1. It's a little weird that you don't see it anywhere above your actions. Might lead to confusion, especially in larger controllers.
  2. Via DHH: "You're calling something in the view that depends on params, which is bad."

The Filter Pattern (The DHH Way)

Finally we get to a pattern that I was aware of, but have avoided because I found it aesthetically displeasing:

class WidgetsController < ApplicationController   before_filter :set_widget, :only => [:show, :edit]    def show; end   def edit; end    private    def set_widget     @widget = Widget.find(params[:id])   end end 

So why didn't I like this? Because before_filter seems like it shouldn't be setting a variable, but modifying things (DHH agreed that before_filter should likely have a different name such as before_action). Also I didn't like the fact that the code is split up into two places.

However, DHH made a single argument that trumped everything else I had considered: "When it comes to setters, you don't care about the implementation, but you care very much that you know it's there." And it's true: the filter isn't doing anything complicated, it's just setting an instance variable and its function is very clear from its name. So when you think of it that way, using a before_filter actually makes all kinds of sense.

Why so many?

There are other ways of achieving this pattern, even gems such as decent_exposure that can automate much of it. So why isn't there a standard solution for this extremely common abstraction "baked in" to Rails? Because at a certain point abstracting behavior that is too simple is more complex than simply not abstracting it at all.

Why did so many patterns evolve for doing the same thing? I lay the blame mostly on both the name and syntax of the before_filter method. When something is called a "filter" you expect it to be manipulating, not setting. In addition (to me at least), the :only and :except syntax doesn't feel right to use in a common case. To me, these keywords ugly up the declaration and should only be used as a last resort.

So what might we do to the Rails syntax to make this pattern a little easier to understand? Here are a few different options I've been thinking about:

class WidgetsController < Application   # Option A   run :set_widget, before: [:show, :edit]    # Option B   before :show, :edit, set: :widget   before :index, run: :prepare    # Option C   before_action :set_widget, only: [:show, :edit]    private    def set_widget     # ...   end    def prepare     # ...   end end 

Option A adds a new run method to the controller syntax that acts as an "every filter". You could specify :before, :after, or :around options and either supply a list of actions or :all for all actions. Two downsides to this: The syntax is a little longer for the case where you want the method to run before all actions, and I don't have a good analog to :except for this option.

Option B takes a different approach and assumes that the arguments are declaring actions instead of methods to run. Here you declare one or more actions (or none for all actions) and you have two options: you can declare a :set key that will call a method called set_value where value is one or more symbols passed into the option, or you can call the :run option which will simply execute methods named as specified. This may seem like an arbitrary design choice, but Rails is full of choices that don't have specific need but rather guide developers down doing the best practice instead of doing something else. Downsides to this are again a lack of a good :except syntax and it reverses the current Rails assumption of declaring methods with before so would likely have some confusion associated if it were adopted.

Option C Is simply renaming before_filter to before_action. Obviously you would have to alias it (perhaps through the Rails 3.x versions), but eventually before_filter would be deprecated. The word filter simply implies a certain type of functionality rather than accurately describing it as simply a way to execute code before an action.

I'm not saying that any one of these options is better than what's already available, I just think that it's interesting that one of the most common patterns in Rails can still have so much difference of implementation around it. The fact that no one "best practice" has become dominant to me implies that there's some room to explore API changes to point people down a best path. What are your thoughts on the controller setter pattern?

Categories
Author

Yesterday it was announced that one of our clients, DealPop, was acquired by Tippr. Tippr, a collective buying daily deals site founded in 2010 and known for their "accelerated deals" model acquired DealPop, a "neighborhood deals" startup from WhitePages Inc. Congratulations to the DealPop team on this great news and for all the hard work, innovation, and energy that was poured into this initiative.

Patti, Senior Project Manager at Intridea, was one of our team members who worked closely with the DealPop team to help bring their product to life:

Last year WhitePages started an initiative to form small teams of startups, and one of those teams was DealPop. They reached out to us at Intridea to help build their product quickly, and we got them to market in only three months.

It was an awesome initiative for a company of that size and age. The team felt really autonomous and close-knit but they still had a lot of support from WhitePages. Working with the team was very collaborative. It was such an engaging and exciting relationship.

Our team worked with DealPop on every aspect of the project, from the initial design brainstorming, to system architecture, to front and backend development. Our teams worked so well together that DealPop invited us out to celebrate their official launch. Patti and Chris, a Senior Partner at Intridea, jumped on the opportunity to meet the DealPop team, clink glasses and help them celebrate their success.

Intridea is the best dev/design service in the US. Thanks for all the great work on DealPop.

Kevin Nakao, COO of WhitePages.com

We like to think that DealPop loved working with us as much as we loved working with them; yesterday Kevin Nakao, COO of WhitePages.com came out to the Twitterverse that he happens to think we're awesome. We'll take it as a sign that the feelings are mutual!

Our relationship with DealPop is the kind of relationship we strive for with all of our clients: engaging, supportive, innovative and mutually beneficial. When we got word of their acquisition, our Presently stream (our enterprise communication application) was abuzz with excitement for the DealPop team.

So we're wishing DealPop and Tippr good luck in their new relationship - a match that couldn't be more perfect. Cheers to good deals all around!

We love our clients! If you're interested in our development, design or mobile services take a look at some of our recent work and contact us today. We will work closely with your team to help turn your ideas into engaging mobile and web applications.

Categories
Author

You've just written a masterpiece of a web app. It's fun, it's viral, and it's useful. It's clearly going to be "Sliced Bread 2.0". But what comes next is a series of unforeseen headaches. You'll outgrow your shared hosting and need to get on cloud services. A late night hack session will leave you sleep deprived, and you'll accidentally drop your production database instead of your staging database. Once you serve up a handful of error pages, your praise-singing users will leave you faster than it takes to start a flamewar in #offrails. But wait! Just as Ruby helped you build your killer app, Ruby can also help you manage your infrastructure as your app grows. Read on for a list of useful gems every webapp should have.

Backups

When you make a coding mistake, you can revert to a good known commit. But when disaster wrecks havoc with your data, you better have an offsite backup ready to minimize your losses. Enter the backups gem, a DSL for describing your different data stores and offsite storage locations. Once you specify what data stores you use in your application (MySQL, PostgreSQL, Mongo, Redis, and more), and where you want to store it (rsync, S3, CloudFiles), Backup will dump and store your backups. You can specify how many backups you'd like to keep in rotation, and there's various extras like gzip compression, and notifiers for when backups are created or failed to create.

Cron Jobs

Having backups configured doesn't make you any less absent minded about running your backups. The first remedy that jumps to mind is editing your crontab. But man, it's hard to remember the format on that sucker. If only there was a Ruby wrapper around cron... Fortunately there is! Thanks to the whenever gem, you can define repetitious tasks in a Ruby script.

Cloud Services

With the number of cloud services available today, it's becoming more common to have your entire infrastructure hosted in the cloud. Many of these services offer API's to help you tailor and control your environments programmatically. Having API's is great, but it's tough to keep them all in your head.

The fog gem is the one API to rule them all. It provides a consistent interface to several cloud services. There are specific adapters for each cloud service. By following the Fog interface, it makes it really easy to switch between different cloud services. Say you were using Amazon's S3, but wanted to switch to Rackspace's CloudFiles. If you use Fog, it's as simple as replacing your credentials and changing the service name. You can create real cloud servers, or create mock ones for testing. Even if you don't use any cloud services, fog has adapters for non-cloud servers and filesystems.

Exception Handling

Hoptoad is a household name in the Ruby community. It catches exceptions created by your app, and sends them into a pretty web interface and other notifications. If you can't use Hoptoad because of a firewall, check out the self-hostable Errbit.

Monitoring

When your infrastructure isn't running smoothly, it better be raising all kinds of alarms and sirens to get someone to fix it. Two popular monitoring solutions are God, and Monit. God lets you configure which services you want to monitor in Ruby, and the Monit gem gives you an interface to query services you have registered with Monit. If you have a Ruby script that you'd like to have running like a traditional Unix daemon, check out the daemons gem. It wraps around your existing Ruby script and gives you a 'start', 'stop', 'restart' command line interface that makes it easier to monitor. Don't forget to monitor your background services, it sucks to have all your users find your broken server before you do.

Staging

Your application is happily running in production, but all of a sudden, it decides to implode on itself for a specific user when they update their avatar. Try as you might, you just can't reproduce the bug locally. You could do some cowboy debugging on production, but you'll end up dropping your entire database on accident. Oops.

It's times like these that you'll be thankful you have a staging environment setup. If you use capistrano, make sure to check out how to use capistrano-ext gem, and its multi-stage deploy functionality. To reproduce your bug on the same data, you can use the taps gem to transfer your data from your production database to your staging database. If you're using Heroku then it's already built-in.

Before you start testing your mailers on staging, do all of your users a favor and install the mail_safe gem. It stubs out ActionMailer so that your users don't get your testing spam. It also lets you send emails to your own email address for testing.

CLI Tools

Thor is a good foundation for writing CLI utilities in Ruby. It has interfaces for manipulating files and directories, parsing command line options, and manipulating processes.

Deployment

Capistrano helps you deploy your application, and Chef configures and deploys your servers and services. If you use Vagrant for managing development virtual machines, you can reuse your Chef cookbooks for production.

Conclusion

All of these gems help us maintain our application infrastructure in a robust way. It frees us from running one-off scripts and hacks in production and gives us a repeatable process for managing everything our app runs on. And on top of all the awesome functionality these tools provide, we can also write Ruby to interact with them and version control them alongside our code. So for your next killer webapp, don't forget to add some killer devops to go along with it.

Categories
Author

I had the opportunity to speak at RailsConf 2011 about OmniAuth, outlining some of the reasoning behind it as well as some current and upcoming features of Intridea's own "authenticate with anything" middleware. While the session wasn't video recorded, a little trick I've picked up is to run a screencasting program in the background while I present to generate a "poor man's Confreaks" version of the talk. Well, that's exactly what I've done for OmniAuth: From the Ground Up!

I'm also embedding the slides below for a "click-through" tour of the talk, but there were a few livecoding sections that are only represented in the video form.

I had a great time at my fourth RailsConf and I hope those who had a chance to attend enjoyed my talk. I also want to say thanks to all of OmniAuth's contributors, they've given me the ability to really ratchet up the awesome on the library and I couldn't have done it without them.

Categories
Author

We know there is an Application class in the Android api and according to the class name it's used for global settings or running entrance. What does it to do for an application? I will dive into it along with some examples in this blog post.

In the Android reference it describes the Application class: "Base class for those who need to maintain global application state. You can provide your own implementation by specifying its name in your AndroidManifest.xml's tag, which will cause that class to be instantiated for you when the process for your application/package is created."

So you can create your own subclass of Application like this:

And specify its name in your AndroidManifest.xml's tag

The Application class is mainly used for some Application level callbacks and for maintaining global Application state.

Application level callbacks

  • onConfigurationChanged( ) Called by the system when the device configuration changes while your component is running.
  • onCreate( ) Called when the application is starting, before any other application objects have been created.
  • onLowMemory( ) This is called when the overall system is running low on memory, and would like actively running processes to tighten their belts.
  • onTerminate( ) This method is for use in emulated process environments. It will never be called on a production Android device, where processes are removed by simply killing them; no user code (including this callback) is executed when doing so.

Maintaining global Application state

Sometimes you want to store data, like global variables which need to be accessed from multiple Activities - sometimes everywhere within the application. In this case, the Application object will help you.

For example, if you want to get the basic authentication data for each http request, you can implement the methods for authentication data in the application object.

After this,you can get the username and password in any of the activities like this:

And finally, do remember to use the Application object as a singleton object:

Categories
Author

Introducing Socialspring - a suite of smart solutions for today's enterprise.

The Socialspring suite private beta launches today, along with its first application, Answers, and you can be the first in line to receive access; sign up now and you'll be the first to receive product announcements, details about release schedules, and you'll get the first opportunity to demo the applications in the suite.

A Fresh Idea

Socialspring is business software, humanized. The suite offers a complete set of tools for internal social collaboration, productivity, expert search and more. Unlike current social enterprise software, Socialspring is not just a dressed-up social network. We’ve re-imagined how business software can mimic real world social connections to help you be more productive and make work a more pleasurable experience overall. Socialspring apps will be united with single sign-on and although all of the apps can be used standalone, the more apps you use within the suite, the more powerful Socialspring becomes for your company.

Answers

Answers is the first application of the Socialspring suite; it's a Q&A platform for the enterprise that unites the collective knowledge of your organization. It captures workplace interactions, encourages participation with seamless integration of a badge and karma system, and promotes the sharing of knowledge among employees within your organization. It does all this (and more!) with a super user friendly interface, because we believe in creating software that is fun and easy to use.

Through participation, your employees will build a centralized (and searchable) knowledge repository. Answers puts the expertise of your entire company at your fingertips. Ask questions, get answers. Answer questions, get recognized.

Sneak Peek

Here is a shot of Socialspring Answers in action! Notice the Q&A functionality, the rating system, search capabilities, as well as the badge and karma points.

Why Answers?

In the modern world, companies are looking to consumer trends to determine their own enterprise strategies. Today's trend is knowledge and easy access to it. As a company grows in numbers and resources, relevant information is obfuscated through traditional means of communication - information is passed person-to-person through email, chat, or phone and then reaches a dead end. Answers allows that information to be captured, preserved and made available to anyone who might need it at the company.

Answers allows all that useful information in a company to be centralized, tagged, and saved for quick, easy access by anyone who needs it - today, tomorrow, or a year from now. Answers helps ease the process of getting new employees bootstrapped; it streamlines protocol for training and communication; it provides administration and other departments within your organization a way to make documents and information available to those that need it. Answers is the always growing, ever improving knowledge-base for your company.

Get On Board!

More information about Answers and Socialspring is coming, and it will go out first to those who sign up. Anticipate announcements regarding additional products in the Socialspring suite, including a core social network, internal link shortening, expert search and several more! So sign up now for the private beta, announcements and information about Socialspring - business software that treats you like a human being!

Categories
Author

Captain Hammer told me they call it bash for a reason... don't say I didn't warn you. Of course I'm talking about my favorite superhero and the default shell in OS X respectively. Now, I'm not here to tell you that using bash is dumb and that you can only be a good developer if you use an alternate shell like ZSH, but I am here to say that when I use bash I feel dumb. Bash just seems to get in my way, probably because I never took the time to properly customize it. But now the hard work of terminal customization has been done for us by the oh-my-zsh community. A big thanks to all that have contributed!

Who is this for?

This overview is geared toward developers that are new to working a lot at the command line or for folks that haven't ever tried to customize their prompt. If you're tired of your ugly and unhelpful default shell settings and aren't sure where to get started with customizing it from scratch then both oh-my-zsh and this walkthrough are for you.

Wait...what is oh-my-zsh again?

Oh-my-zsh is available on github where it's described as:

"A community-driven framework for managing your zsh configuration. Includes optional plugins for various tools (rails, git, OSX, brew,...), nearly 80 terminal themes, and an auto-updating tool so that you can keep up with the latest improvements from the community."

OK, I'm convinced... help me get it installed!

There is a great README provided on the github page referenced above, but I'll highlight a few items here. The first and most critical step is one you actually won't find in the README... fork the repository and get a copy that you can tweak on yourself. The main reason is so you have a version of oh-my-zsh that can easily be installed on any server with all your custom theme settings and aliases. We'll get to customization later but keep in mind that installing oh-my-zsh is not at all permanent. There is a great uninstaller so it's easy to try out one fork and remove all traces of that code easily so you can install another fork (probably your own) later. Or if you try it out but hate it, getting back to your old prompt is a single "uninstall_oh_my_zsh" command away. For now, let's just dive in!

To get oh-my-zsh installed simply issue this single command in your current terminal:

wget --no-check-certificate https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh -O - | sh 

Note: even if you're doing this from your own fork it's still going out to Robby Russell's git repo to do the clone. I'll help you fix that later.

One of two things will happen next. If you're on OS X and don't have wget installed or accessible to your path then you'll get an error. If that's the case then go check out Homebrew. Conveniently the demo they give is installing wget:

brew install wget 

You'll actually need to have Homebrew installed before you can run the above command, but we'll leave that as an exercise to the reader. If you're on linux and don't have wget installed then just add it with your distro's package manager. On Ubuntu:

sudo apt-get install wget 

Once you have your wget error resolved re-run the installer command and proceed.

If you didn't get an error during installation then you should receive something similar to the following terminal output:

oh-my-zsh installation terminal output

All that's left to do it open a new tab or terminal window and you're off and running! The new theme that you see is the robbyrussell theme. It's pretty cool, but it might not include everything you want out of your prompt. In a second I'll show you my theme and help you create your own, but first let's take a side trip and make sure our .zshrc file is setup properly.

Using RVM with ZSH (you do use RVM don't you?!?)

If you haven't taken a look at your .zshrc file yet I'd recommend doing so now. It'll be installed as a hidden "dotfile" in your home directory located at: ~/.zshrc. Just after installation mine looks like this:

# Set name of the theme to load. # Look in ~/.oh-my-zsh/themes/ # Optionally, if you set this to "random", it'll load a random theme each # time that oh-my-zsh is loaded. export ZSH_THEME="robbyrussell"  # Set to this to use case-sensitive completion # export CASE_SENSITIVE="true"  # Comment this out to disable weekly auto-update checks # export DISABLE_AUTO_UPDATE="true"  # Uncomment following line if you want to disable colors in ls # export DISABLE_LS_COLORS="true"  # Uncomment following line if you want to disable autosetting terminal title. # export DISABLE_AUTO_TITLE="true"  # Which plugins would you like to load? (plugins can be found in ~/.oh-my-zsh/plugins/*) # Example format: plugins=(rails git textmate ruby lighthouse) plugins=(git)  source $ZSH/oh-my-zsh.sh  # Customize to your needs... export PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin 

Sweet! The PATH directive was carried over from the ~/.bash_profile! Let's clean this up a bit and try out another theme. Remember to see the theme change you have to open a new tab or window, or quit and restart terminal so your .zshrc changes can be loaded. The last line is what you need to allow RVM to dynamically manage your path. You shouldn't put anything below that last line. This isn't a tutorial on how to setup RVM, so if you get stuck please head over to their awesome site for more info on installation and ZSH integration.

# Path to your oh-my-zsh configuration. export ZSH=$HOME/.oh-my-zsh  # specify a theme export ZSH_THEME="Soliah"  # load from the available list of plugins at ~/.oh-my-zsh/plugins plugins=(git git-flow rails textmate ruby cap brew gem github mysql osx vagrant)  source $ZSH/oh-my-zsh.sh # source ~/.git-flow-completion.zsh #you have to paste that file to that location then  export PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin:/usr/bin/mysql  # load RVM [[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm" 

Much better :) You can see I added "/usr/bin/mysql" to the path because I need it (each directory on the path is separated by a colon). Feel free to ignore that if you don't use MySQL.

Theme settings

As promised, here is the theme that I am currently running:

oh-my-zsh j2fly theme screen shot

Below is the zsh-theme file that I'm specifying in my .zshrc config. This theme was made possible by combining ideas from many of the excellent themes that are already out there and adding a few of my own tweaks. The color scheme was inspired from a post I read a year or so ago by Steve Losh that introduced me to oh-my-zsh. Again, a huge thanks to all the authors that have contributed forks and themes.

# Shows little symbol '±' if you're currently at a git repo and '?' all other times function prompt_char {     git branch >/dev/null 2>/dev/null && echo '±' && return     echo '?' }  function virtualenv_info {     [ $VIRTUAL_ENV ] && echo '('`basename $VIRTUAL_ENV`') ' }   # Build the main prompt if [[ "$TERM" != "dumb" ]] && [[ "$DISABLE_LS_COLORS" != "true" ]]; then     PROMPT='%{$fg[magenta]%}%n%{$reset_color%} at %{$fg[yellow]%}%m%{$reset_color%} in %{$fg_bold[green]%}${PWD/#$HOME/~}%{$reset_color%}$(git_prompt_info)${return_code}$(git_prompt_status)%{$reset_color%} $(virtualenv_info)$(prompt_char) '      ZSH_THEME_GIT_PROMPT_PREFIX=" on %{$fg[magenta]%}"     ZSH_THEME_GIT_PROMPT_SUFFIX="%{$reset_color%}"     ZSH_THEME_GIT_PROMPT_DIRTY=""     ZSH_THEME_GIT_PROMPT_CLEAN=""      # Display exitcode on the right when >0     return_code="%(?..%{$fg[red]%}%? ?%{$reset_color%})"      # Loads rvm info to the right side of the zsh prompt showing: ruby-version@gemset-name     RPROMPT='$(~/.rvm/bin/rvm-prompt)'      # Displays different symbols (simultaneously) depending on the current status of your git repo.     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]%} ?" else     PROMPT='[%n@%m:%~$(git_prompt_info)] %# '      ZSH_THEME_GIT_PROMPT_PREFIX=" on"     ZSH_THEME_GIT_PROMPT_SUFFIX=""     ZSH_THEME_GIT_PROMPT_DIRTY=""     ZSH_THEME_GIT_PROMPT_CLEAN=""      # Display exitcode on the right when >0     return_code="%(?..%? ?)"      RPROMPT='${return_code}$(git_prompt_status)'      ZSH_THEME_GIT_PROMPT_ADDED=" ?"     ZSH_THEME_GIT_PROMPT_MODIFIED=" ?"     ZSH_THEME_GIT_PROMPT_DELETED=" ?"     ZSH_THEME_GIT_PROMPT_RENAMED=" ?"     ZSH_THEME_GIT_PROMPT_UNMERGED=" ?"     ZSH_THEME_GIT_PROMPT_UNTRACKED=" ?" fi 

Awesome aliases and plugins

So now that we have the theme setup and RVM loaded properly it's time to show you some of the awesome aliases and plugins that are available. I recommend loading up the ~/.oh-my-zsh directory in your favorite editor and browsing around to get familiar because there is a goldmine of syntactic sugar for many of the long / hard to remember operations we perform every day. I'll list a few of the ones I use on a daily basis and what location they're found in.

Aliases

| Alias           | Full Command                       | Location                           | |:----------------|:-----------------------------------|:-----------------------------------| | l               | ls -la                             | lib/aliases.zsh                    | | ll              | ls -l                              | lib/aliases.zsh                    | | ..              | cd ..                              | lib/directories.zsh                | | ...             | cd ../..                           | directories.zsh                    | | mcd(my_folder)  | mkdir -p my_folder && cd my_folder | lib/directories.zsh                | | gst             | git status                         | plugins/git/git.plugin.zsh         | | gb              | git branch                         | plugins/git/git.plugin.zsh         | | gca -m "commit" | git commit -a -m "commit"          | plugins/git/git.plugin.zsh         | | gp              | git push                           | plugins/git/git.plugin.zsh         | | gco             | git checkout                       | plugins/git/git.plugin.zsh         | | bi              | bundle install                     | plugins/bundler/bundler.plugin.zsh | | bu              | bundle update                      | plugins/bundler/bundler.plugin.zsh | 

When you need a break to laugh, load up the "lol"" plugin (plugins/lol/lol.plugin.zsh) and get fun/silly aliases like:

| Alias     | Full Command | |:----------|:-------------| | rtfm      | man          | | hai       | cd           | | nomz      | ps -aux      | | kthxbai   | halt         | | icanhas   | mkdir        | | donotwant | rm           | | dowant    | cp           | 

Plugins*

| Cmd (type what's in quotes) | What it does                     | Location                   | |:----------------------------|:---------------------------------|:---------------------------| | "tab" + enter               | New term tab w/ same working dir | plugins/osx/osx.plugin.zsh | | "rake" + space, hit tab key | Autocomplete avail rake tasks    | Not sure actually          | | "cap" + space, hit tab key  | Autocomplete avail cap tasks     | plugins/cap/cap.plugin.zsh | | "brew" + space, hit tab key | Autocomplete avail brew commands | plugins/brew/_brew         | 

*Some of the plugins are broken (or were for me anyway), so if you want all the plugins to work (with the tab completion of cap and rake tasks, as well as the "tab" command itself to open a new tab with your current path preserved), you'll have to fork from my repo where I have fixed them. I've submitted a pull request for Robby to get these changes back upstream to the the main repo.

Tab completion

ZSH is great at tab completion and more specifically progressive tab completion. You can tab through some directories and hit enter to accept that directory as the one you want at the first level, then continue tabbing through the next deepest set of directories without executing the command until you're ready. In my experience, bash would commit your current text as a command if you hit enter mid-tab completion. Try out tab completion for yourself! You can even tab complete to remote servers. If you're trying to scp a file to a remote server and you don't remember what user directory you want to put it under you can do something like this:

Tab completion to remote server

Customization

OK, so you've tried out some of the cool stuff ZSH and specifically oh-my-zsh has to offer and you want to make some changes to your own fork. Great! Check out what I customized and then poke around and hack on oh-my-zsh until you've made it perfect for you.

Files you'll want to edit:

  • install.sh
  • your_theme.zsh-theme
  • templates/zshrc.zsh-template
  • README
  • custom/my_cool_aliases.zsh

install.sh

Just because the installer takes a git repo at the command line doesn't mean that is the git repo it'll actually clone to your ~/.oh-my-zsh folder during install. If you look at the install.sh file in the "tools" folder you'll see line 8 (as of this writing) is where the git repo is specified. Mine is:

/usr/bin/env git clone https://github.com/j2fly/oh-my-zsh.git ~/.oh-my-zsh 

Make sure to change that URL to be your repo's URL.

Your Theme

Just add your own something.zsh-theme to the themes folder and specify it in your templates/zshrc.zsh-template so it's the theme specified when you install from your fork.

zshrc.zsh-template

Edit this file to customize what the .zshrc file will look like when you install oh-my-zsh from your fork. For instance, I include the RVM hooks in my fork (commented out), and I make sure that the theme that is defined is the "j2fly" theme since that is the one I customized for myself.

Readme

Now I'll probably catch flack for telling you to edit the README of an open source project, but hey... I want the install URL to be easily accessible. The install command for me to use my fork is:

wget --no-check-certificate https://github.com/j2fly/oh-my-zsh/raw/master/tools/install.sh -O - | sh 

Custom

So that you don't have to dirty up any of the other files in the "lib" or "plugins" directories just to add some of your own aliases, oh-my-zsh will automatically load any files with the .zsh extension from the "custom" folder. I have some cool aliases defined of my own including:

alias rvm_install_shortcut='bash < <(curl -s https://rvm.beginrescueend.com/install/rvm)' 

At first glance that might not seem like much of a shortcut, but remember ZSH can tab-complete almost anything and since usually at this point RVM isn't installed yet, all I have to do is type "rvm", hit the tab key and then it'll complete the install alias to go install me some tasty RVM!

Protip

If you want to be able to customize your oh-my-zsh install directly in place at ~/.oh-my-zsh and push those changes to github without having to maintain a separate repo, you can do it with one small change. Open the ~/.oh-my-zsh/.git/config file and change the remote origin to be your git clone URL (which has read and write access).

Change this:

[remote "origin"]     fetch = +refs/heads/*:refs/remotes/origin/*     url = https://github.com/j2fly/oh-my-zsh.git 

To this:

[remote "origin"]     fetch = +refs/heads/*:refs/remotes/origin/*     url = git@github.com:j2fly/oh-my-zsh.git 

Using your clone URL, not mine :)

Making it all rock with a dark background and Visor

I have a 1920x1200 display and I use Visor exclusively for working with my terminal. I find that even with all the screen real-estate that I could possibly want, the terminal just isn't something I want to dedicate to a portion of pixels on my screen. Visor helps keep the terminal front and center when you need it and totally hidden when you don't.

The key bindings to "fade" or "fly in" the terminal window are ctrl+` or if you have the double tap ctrl option enabled then you can hit ctrl+ctrl to pop open the window. I prefer to leave the double tap option off however as I find that I usually only accidentally trigger the visor when it's enabled.

With today's widescreen monitors I think it makes the most sense to have the terminal fly in from the right hand side. I also keep my dock attached to the left side of my screen so that I can work at full height in the "middle". I have my terminal window settings configured to have it take up 129 columns and 24 rows. This makes the terminal fly in to the perfect spot to leave the other half of my screen (minus the room for the dock positioned on the left) available for a browser or code.

I use the awesome SizeUp and Cinch apps to allow me to position any given window to either the left or right half of my screen (like the windows 7 snap feature) which makes this setup even cooler.

My full desktop with visor open

If you like Visor, I highly recommend that you check out TotalFinder as well. It's also from BinaryAge, an indy Mac software shop so support both them and Irradiated Software with a purchase or donation if you like their tools!

Wrap up

Hopefully you got some insight into how I have my terminal setup and it's inspired you to go customize your own prompt and maybe even take a look at Visor. It's ok to spend a few hours getting things setup just the way you like so that you can have a more pleasant terminal experience every time you sit down to code. Just remember to commit your changes to your github fork so you can easily restore your oh-my-zsh config when you reformat your laptop. I also install my fork of the prompt on servers that I am the sys admin for!

Post any questions or share your thoughts in the comments below. I look forward to hearing from you about your own oh-my-zsh experience!

Categories
Author
Subscribe to