Entries tagged with “Tips”
- All (14)
- Entries (7)
- Links (7)
- Photos (0)
Easy Deploys to Multiple Environments with Capistrano
At Viddler, we’re switching to using Git and Capistrano for our internal projects, and I was tasked with setting up the system to deploy our code to both staging and production environments. Capistrano doesn’t have built-in environment switching, but it’s dead simple to add it yourself.
The key to getting this to work is to utilize Capistrano’s ability to chain tasks–if you run cap task1 task2, it will run the two commands in the order you listed them. Variables are shared between the tasks, so if you set a variable in task1, task2 will be able to access it. To get multiple environments working, you just create tasks to set environment variables, which you call before the actual task you want to run.
The first step is to figure out which variables you need to change, and then move them into their own tasks. Here’s an example of the tasks we added:
desc "Run on staging server"
task :staging do
server "staging.myserver.com", :app, :web, :db, :primary => true
end
desc "Run on production server"
task :production do
server "myserver.com", :app, :web, :db, :primary => true
end
Now, if you want to deploy to staging, just run cap staging deploy, and for production run cap production deploy. Easy.
The Perfect Git Workflow for a One Person Project
A few months ago, I started investigating Git, and I fell in love with how much easier it made managing my code. I’m managing the source code to this site with Git, and along the way I’ve come up with a pretty good workflow for myself. The basic steps are:
- Branch
- Commit
- Rebase
- Merge
- Deploy
Let’s go through each one to see how it all works together.
Branch
With SVN, I found myself hating branching–it was always a complicated procedure, and I could never remember how to do it. In Git it’s as easy as git checkout -b <branch-name>, and you’re ready to go. Once you have a branch, you can modify it however you want, and you don’t have to worry about interfering with the master branch. In order to keep your master branch bug free, commit only to branches, not to master itself.
In addition to creating new branches for major features, I always have a few branches around that I pop into for certain things:
- “design” - any changes I want to make to the design go here
- “optimize” - optimizations to the site
- “bugfixes” - a place to work on minor bugfixes
Having these branches allows me to make small fixes to the site, and if it turns out it’s more than just a small fix, it doesn’t interfere with anything else.
Commit
In the Subversion world, it’s a pretty common practice to make very large commits, consisting of many changes. With Git, you should constantly be committing. By making many commits, you make it easier to find bugs you may have introduced, and it makes it a lot easier to track your progress. If you don’t like the thought of wading through long lists of commits in your logs, don’t worry–before bringing it over to the master branch, you can consolidate things with interactive rebasing, but while you’re hacking away on a branch, it really is advantageous to have many small commits.
Rebase
Rebasing is one of the harder things to grasp when you’re first learning about Git. For in-depth coverage of the topic, check out the Rebasing page in the Git Community Book. In a nutshell, doing git rebase master takes any commits to master and inserts them into your current branch, so you can then make sure your new code still works, and it’s a lot less hazardous than doing a merge. Rebasing your branch before putting into master is really important because it allows you to deal with any merge issues before the code goes to your main branch. To rebase, just run git rebase master.
Merge
After rebasing the branch, it’s safe to merge it into master. Since I’ve already dealt with any merge issues with the previous step, it’s as simple as checking out the master branch and running git merge <branch-name>
Deploy
I use Capistrano to deploy my code, so I’m constantly typing git push followed by cap deploy to deploy changes to my server. To make it easier, I just put both commands into one git alias:
deploy = !git push && cap deploy
Now I just need to run git deploy and it automatically pushes all of my changes to the remote Git repository and then deploys the site using Capistrano. Here’s some more information about Git aliases.
Useful tools
Though I primarily use Git through the command line, I really like using GitX to visualize branches. To host my repositories on my server, I use Gitosis, though if I had a few more projects, I’d dole out the money for a paid account at GitHub.
Have a great Git workflow? Think mine’s terrible? Let me know in the comments!
Sass Without the Hass(le)
For a recent project, I decided to try out Sass, a “meta-language on top of CSS,” which allows to do all sorts of neat things like use variables, do math, and have mixins. The only problem: since you’re not writing CSS, it has to be compiled whenever you want to view your page, which can be pretty annoying if you’re just working on a static template (which I was).
At first, I was using the standard command: sass input.sass output.css, but that became too tiresome, and I was struck with an idea–what if I just created a server solely for serving the compiled CSS file? Using Sinatra, I was able to make a dead easy way to use Sass while working on a static template. Follow along to see how you can do this yourself.
First, make sure you’ve got the haml and sinatra gems installed:
gem install haml sinatra
Now, in your development directory, create a file called app.rb and paste the following code:
require 'rubygems'
require 'sinatra'
require 'haml'
get '/style.css' do
headers 'Content-Type' => 'text/css; charset=utf-8'
sass :style
end
Now, create a views/ directory in that same folder, and drop a style.sass file in there. This is where you’ll be writing your Sass. Now, you need to start up your Sinatra server, and to do that, just run the following command:
ruby app.rb
Now, if you go to http://localhost:4567/style.css, you’ll see your compiled CSS, and every time you update your Sass file, the code is recompiled. Just change the CSS <link> tag in your HTML template to point to the style.css file, and you’re ready to go!
How to Take Better Photos
I’ve been into photography for a while now, and while I definitely don’t consider myself an expert on any level, I’ve come across a lot of tips over the years that have really helped to improve my photos. I’ve collected together a few of my favorite ones below, in the hopes they’ll help someone else.
Constrain yourself
Peeling Paint and Window, taken with my 50mm lens
Next time you go out to take some photos, give yourself a constraint. For example, maybe just bring one lens, or choose just one focal length to shoot at (a prime lens works perfectly for this). When I went to Italy, I brought 2 lenses, one of which appeared to be broken when I got there, so I had to spend the week using only my 50mm lens. This actually turned out to be a blessing in disguise, as I ended up with some of my favorite photos I’ve ever taken. Another great exercise in constraints is to place a piece of paper on the ground, and then take 50 photos without taking your feet off the paper. Really, you’re just trying to get yourself to look at the world in a different way.
Take your camera everywhere
A lot of great photos come about because someone was in the right spot at the right time. However, in order to capture the moment, you have to have a camera to do it with. If you’re not carrying your camera with you everywhere, you’re probably missing out on a lot of opportunities. One of the best things I ever did was purchase a point and shoot camera that fit in my pocket–now I can carry it wherever I go, ready for the unexpected.
Stop worrying about equipment
Weeping Lily, taken on a tiny point and shoot!
So many times, I’ve caught myself saying, “I would love to take that photo, but my camera’s not good enough.” This is stupid. Ansel Adams didn’t have a fancy 20 megapixel DSLR, and he took photos better than most people can even dream of. Instead, work with what you have–it’s the thought behind the photo, not the camera, that truly matters. I’ve taken great photos with tiny little point and shoot cameras, and I’ve taken horrible photos with my big DSLR. The sooner you realize your equipment doesn’t matter, the better.
Ask for critique
This photo of my sister became a whole lot better after having it critiqued on Flickr.
Some of the best photography experiences I’ve had were when I’ve had my photos critiqued by others, and when I’ve critiqued others. Having someone else take a look at your work can be incredibly helpful, as they’ll often notice things you never saw yourself, and critiquing other people’s photos can help you find new techniques and approaches to photography. If you have a group of friends that are all into photography, maybe you can meet every so often and swap shots. Or, join a site like Flickr, and start commenting on photos by other users. Soon enough, they’ll be commenting back on yours, and you’ll start seeing your photos in a whole new light.
Take lots of photos
Memory cards are cheap, so why skimp on photos? I’ve found that the more photos I take, the better I become at photography. But it’s not just about taking lots of photos, it’s about going back and seeing what your mistakes were and learning from them. If you aren’t taking a whole bunch of photos, you’re not going to learn from your mistakes, because you won’t be making them.
Don’t think about Photoshop
This photo, Dreaming, was weak from the start, and my attempts to save it really didn’t do much.
For a while, I was really into Photoshop–nearly every photo I took was manipulated in some way to make it better, and I started to even think about how I was going to process an image before I even pressed the shutter button. This is bad. Focus on making your photos as perfect as possible before they get to your computer, and you’ll end up with a much nicer finished product. That’s not to say you shouldn’t tweak photos afterwards, but you just have to remember that taking an amazing photo isn’t about what filters you use, but rather about how you compose the image in the viewfinder.
Hopefully these tips are helpful, and if you have any to share, make sure to leave comments below!
Making Better Use of named_scope
In Ruby on Rails 2.1, a great little feature called named_scope was added that really makes complicated finds a whole lot easier. I’m going to walk through one way you can use scopes to clean up your code, and if you want more information, Ryan Daigle’s post is a good starting point.
The Situation
For a project I’m working on, users can submit reviews, and I needed a way to access a user’s friends’ reviews. At first, I considered adding a method like the following to my User model:
class User < ActiveRecord::Base
def friends_reviews
Review.find(:all,
:joins => "JOIN friendships ON user_id = #{self.id}",
:conditions => "friendships.friend_id = reviews.user_id"
)
end
end
Named Scopes to the Rescue
While this method would work fine, there are several issues. For one, what if I want to change parameters on the find, like limiting it to 5 entries, or sorting by date? I would have to add parameters to the method, and it would start to get complicated. Instead, I created a scope in my Review model:
class Review < ActiveRecord::Base
named_scope :by_friends_of, lambda { |user|
{
:joins => "JOIN friendships ON user_id = #{user.id}",
:conditions => "friendships.friend_id = reviews.user_id"
}
}
end
Now, to get the reviews I want, I can call Review.by_friends_of(user) and it will get me reviews by user’s friends. What’s even better, since it’s a scope, I can modify it. For instance, Review.by_friends_of(user).all(:limit => 10, :order => "created_at DESC") will limit it to 10 reviews, sorted by creation date. I can even use other scopes I might have created, like: Review.by_friends_of(user).published.all(:limit => 20), and so on.
Scopes are super useful, and recently I’ve started to use them for just about everything. Definitely try them out, they’ll make your code a lot more efficient and useful.
Resizing Rounded Rectangles in Photoshop
In the past, I’ve always dreaded working with rounded rectangles in Photoshop, because they’re just so annoying to resize. If you try to change the object’s height or width, it distorts the corners, making things look pretty bad. Today, I found a way to resize them using the direct selection tool, and it has already made my life a whole lot easier. Check out the screencast I put together to find out how.
Simple PHP Caching Using Output Buffering
I’ve worked on quite a few PHP projects recently, and all of them have required some form of caching. From working with each, I’ve come up with a pretty efficient method for caching code using PHP’s output buffering. It ends up being really quick and super flexible.
Output Buffering Basics
Output buffering is a pretty simple concept: instead of letting PHP return data to your user’s browser, you capture it and store it in a “buffer,” and you can decide what to do with it. Here’s a simple example:
ob_start();
echo "Hello! This is buffered.";
$buffer = ob_get_clean();
Let’s go through the code line-by-line. The first line calls ob_start() (docs), which starts output buffering. The next line normally would be sent to the browser. Instead, since I called ob_start(), it gets stored in our buffer. The third line takes the current buffer and assigns it to the $buffer variable and stops the current buffer, all using the ob_get_clean() function (docs). It’s really simple stuff, and it becomes very powerful when used correctly.
How Caching Will Work
For this post, I’m going to be caching a simple API, and the general process will work like this:
- A user makes an API call, something like
http://mysite.com/api/?method=myapp.search&type=people&query=Kyle - If a cache file exists for the call, and it is younger than 15 minutes, skip to #6.
- Start buffering PHP’s output.
- Run the code to process the request.
- Save the contents of the buffer to a file, with a unique filename.
- Return result to the user.
Where Cached Output Will Be Saved
To save the output, I’m going to be creating a file for each unique request. For this application, the request will be unique based on the GET parameters passed. To do this, I’ll be creating an MD5 hash of an alphabetical list of GET keys and values. Here’s the function:
function cache_key() {
$keys = array();
foreach($_GET as $key => $value) {
$keys[] = $key . "=" . $value;
}
sort($keys);
return md5(implode('&', $keys));
}
function cache_filename() {
globals $cache_dir;
return $cache_dir . '/' . cache_key() . '.cache';
}
Please note that this will have to be customized based on what exactly you’re caching. For instance, if you’re caching individual pages, you may want to create the key using the path to the page. Whatever it is you’re using, just make sure it is unique and consistent for each page.
Checking The Cache
When a request is made, it’s necessary to first check to see if it has already been cached, and, if it has, whether the cache hasn’t expired. I’ll be using the filesystem to achieve this:
$cache_time = 15*60; // 15 minutes in seconds
function cache_exists() {
globals $cache_time;
if(@file_exists(cache_filename()) && time() - $cache_time < @filemtime(cache_filename())) {
return true;
} else {
return false;
}
}
So what exactly is going on here? If you take a close look, we’re using the file_exists() (docs) and filemtime() (docs) functions to see if the cache file already exists and, if it does, whether it’s recent enough to serve (in this case, if it’s less than 15 minutes old, the function returns true). I’m placing @ signs before these two functions so that, if they fail, it doesn’t return an error. Instead, the function will just return false and the code will run as if no cache file exists.
Putting It All Together
Now, it’s time to get everything working together. First, a couple of necessary functions for saving and reading the cache:
function read_cache() {
return file_get_contents(cache_filename());
}
function save_cache($value) {
$fp = @fopen(cache_filename(), 'w');
@fwrite($fp, $value);
@fclose($fp);
}
Now, a few calls to wrap around your code:
function start_cache() {
if(cache_exists()) {
echo read_cache();
exit();
} else {
ob_start();
}
}
function stop_cache() {
$data = ob_get_clean();
save_cache($data);
echo $data;
}
And to implement it, this is all you need to do:
start_cache();
// Your code that needs to be cached
stop_cache();
And you’re done! All-in-all, it’s a very simple way to achieve a very powerful result.
Drawbacks to This Method
The first thing you want to keep in mind when using this caching method is that it caches the entire page. This can be good: if everyone visiting the page sees the same content anyways, why not cache it for everyone? However, if you’re serving a page that appears different to different users, it can be a bad idea. For instance, what if an administrator visits the page, and it gets cached? When the next non-administrator visits, they’re going to see all the administration information. Bad news.
Also, due to the simplicity of this method, there’s no way to easily expire the cache of a single page. Let’s go back to the blog entry example. If you decide to make a change to the entry, you’ll have to wait at least 15 minutes before the cache is cleared, or you have to go in and delete all the cache files (since it’s difficult to determine which file goes with which page). For many applications, this probably won’t an issue, but it’s something to keep in mind.
Download the Source
Hopefully, this was helpful. If you’d like to download the entire source, you can grab it here.
