This error is due to Ruby not being able to find the certification authority certificates (CA Certs) used to verify the authenticity of secured web servers. The solution is to download the this ca-bundle.crt into your application’s lib/ directory:
Then add the following code to config/initializers/fix_ssl.rb:
The standard way of deploying rails applications is to serve a static maintenance page while the code is being updated, to prevent errors being thrown by the user and to prevent writes happening to your database. This is all fine and dandy in the real world but in Facebook land we run into issues.
Facebook will always send a POST on the initial iframe request for security reasons, and this can be to any end-point in our application, while in reality, this should be treated as a GET.
So, the first time a page of your app is requested by user, Facebook sends a POST request. If you’re currently in maintenance mode you’re going to get a big 405 Method not allowed error.
To fix this we need to tell nginx to serve your maintenance page to POST requests, as well as GET requests. We can do this by updating your servers config files. Say your server config initially looks like this:
server {# all your other server stuff# ...# show maintenance page if exists if(-f $document_root/system/maintenance.html){
rewrite ^(.*)$ /system/maintenance.html break;
break;
}}
Add the following location rule to allow nginx to serve the page for POST requests:
server {# all your other server stuff# ...# show maintenance page if exists if(-f $document_root/system/maintenance.html){
rewrite ^(.*)$ /system/maintenance.html break;
break;
}# serve maintenance page to POST requestslocation= /system/maintenance.html {
post_to_static on;
}}
Reload your nginx config and everything should be rocking as expected.
Trying to use send_file from your Rails 3 app and getting a file with a size of zero bytes? It’s more than likely that you’re using nginx and haven’t setup your app to use send_file properly.
Open up your config/environments/production.rb file and find the following lines:
# Specifies the header that your server uses for sending filesconfig.action_dispatch.x_sendfile_header="X-Sendfile"# For nginx:# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'
Then comment out the first config.action_dispatch.x_sendfile_header line and uncomment out the second. So it should look like this:
# Specifies the header that your server uses for sending files# config.action_dispatch.x_sendfile_header = "X-Sendfile"# For nginx:config.action_dispatch.x_sendfile_header='X-Accel-Redirect'
Written by Redis creator, Salvatore Sanfilippo, and key contributor, Pieter Noordhuis, the Redis Book will show you how to work with different data structures, how to handle memory, replication, and the cache itself, and how to implement messaging, amongst other things! Buy the book
Redis is an extremely fast, atomic key-value store. It allows the storage of strings, sets, sorted sets, lists and hashes. Redis keeps all the data in RAM, much like Memcached but unlike Memcached, Redis periodically writes to disk, giving it persistence.
Redis is an open source, advanced key-value store. It is often referred to as a data structure server since keys can contain strings, hashes, lists, sets and sorted sets.
You can run atomic operations on these types, like appending to a string; incrementing the value in a hash; pushing to a list; computing set intersection, union and difference; or getting the member with highest ranking in a sorted set.
In order to achieve its outstanding performance, Redis works with an in-memory dataset. Depending on your use case, you can persist it either by dumping the dataset to disk every once in a while, or by appending each command to a log.
Lastly, create an initializer in config/initializers/redis.rb and add the following:
$redis=Redis.new(:host=>'localhost',:port=>6379)
This will create a new instance of the Redis client, connected to localhost:6379 (the default), and store it in the global variable $redis.
Let’s check that everything is working by firing up rails console:
>$redis=>#<Redis client v2.1.1 connected to redis://localhost:6379/0 (Redis v2.2.2)> >$redis.set('chunky','bacon')=>"OK">$redis.get('chunky')=>"bacon"
Example Uses in Rails
User Friendships
The first example I’ll show you is modelling friendships using ActiveRecord and Redis. We’ll be using sets to store the friendship data. Here is our User model:
classUser<ActiveRecord::Base# follow a userdeffollow!(user)$redis.multido$redis.sadd(self.redis_key(:following),user.id)$redis.sadd(user.redis_key(:followers),self.id)endend# unfollow a userdefunfollow!(user)$redis.multido$redis.srem(self.redis_key(:following),user.id)$redis.srem(user.redis_key(:followers),self.id)endend# users that self followsdeffollowersuser_ids=$redis.smembers(self.redis_key(:followers))User.where(:id=>user_ids)end# users that follow selfdeffollowinguser_ids=$redis.smembers(self.redis_key(:following))User.where(:id=>user_ids)end# users who follow and are being followed by selfdeffriendsuser_ids=$redis.sinter(self.redis_key(:following),self.redis_key(:followers))User.where(:id=>user_ids)end# does the user follow selfdeffollowed_by?(user)$redis.sismember(self.redis_key(:followers),user.id)end# does self follow userdeffollowing?(user)$redis.sismember(self.redis_key(:following),user.id)end# number of followersdeffollowers_count$redis.scard(self.redis_key(:followers))end# number of users being followeddeffollowing_count$redis.scard(self.redis_key(:following))end# helper method to generate redis keysdefredis_key(str)"user:#{self.id}:#{str}"endend
It is all pretty simple. We’re using the following set commands: sadd, srem, smembers, sinter, scard, sismember and the multi command. An overview of the commands is provided below:
Add member to the set stored at key. If member is already a member of this set, no operation is performed. If key does not exist, a new set is created with member as its sole member.
Marks the start of a transaction block. Subsequent commands will be queued for atomic execution using EXEC.
High Score Table
We can construct a simple high score table using Redis sorted sets:
classUser<ActiveRecord::Base# log high scoredefscored(score)ifscore>self.high_score$redis.zadd("highscores",score,self.id)endend# table rankdefrank$redis.zrevrank("highscores",self.id)+1end# high scoredefhigh_score$redis.zscore("highscores",self.id).to_iend# load top 3 usersdefself.top_3$redis.zrevrange("highscores",0,2).map{|id|User.find(id)}endend
Adds the member with the specified score to the sorted set stored at key. If member is already a member of the sorted set, the score is updated and the element reinserted at the right position to ensure the correct ordering. If key does not exist, a new sorted set with the specified member as sole member is created.
Returns the rank of member in the sorted set stored at key, with the scores ordered from high to low. The rank (or index) is 0-based, which means that the member with the highest score has rank 0.
Returns the specified range of elements in the sorted set stored at key. The elements are considered to be ordered from the highest to the lowest score. Descending lexicographical order is used for elements with equal score.
If you want to use Redis as your cache store, then look no further than Redis Store by Luca Guidi. Redis Store provides namespaced Rack::Session, Rack::Cache, I18n and cache Redis stores for Ruby web frameworks. It allows you to use Redis as your Rails cache store, session store and integrates well with Rack::Cache.
Then update your config/environments/production.rb:
config.cache_store=:redis_store
Then you’re good to go. Your cache store should now be using Redis.
Monitoring Redis
If you’re using Redis on your server and you have daemonize set to yes in your redis.conf, you need to monitor it. Below are an example Monit and God script:
Monit
check process redis
start program="/usr/bin/redis-server /etc/redis/redis.conf"
stop program="/usr/bin/redis-cli -p 6379 shutdown"
with pidfile /var/run/redis.pid
group redis
%w{6379}.each do |port|
God.watch do |w|
w.name ="redis"
w.interval = 30.seconds
w.start ="/usr/bin/redis-server /etc/redis/redis.conf"
w.stop ="/usr/bin/redis-cli -p 6379 shutdown"
w.restart ="#{w.stop} && #{w.start}"
w.start_grace = 10.seconds
w.restart_grace = 10.seconds
w.start_if do |start|
start.condition(:process_running)do |c|
c.interval = 5.seconds
c.running =false end
end
end
end
Redis and Unix Sockets
Redis 2.2 introduced the ability to connect to Redis via unix sockets. To allow this functionality you need to uncomment the following line in your redis.conf:
unixsocket /tmp/redis.sock
Then you can connect to Redis in your app, change the contents of your config/initializers/redis.rb, to this:
$redis=Redis.new(:path=>"/tmp/redis.sock")
Below are some rough benchmarks from my MacBook Pro:
~ redis-benchmark -q
PING (inline): 54347.82 requests per second
PING: 52083.33 requests per second
MSET (10 keys): 28571.43 requests per second
SET: 48309.18 requests per second
GET: 49504.95 requests per second
INCR: 47846.89 requests per second
LPUSH: 48309.18 requests per second
LPOP: 49751.24 requests per second
SADD: 48543.69 requests per second
SPOP: 51282.05 requests per second
LPUSH (again, in order to bench LRANGE): 48076.92 requests per second
LRANGE (first 100 elements): 34129.69 requests per second
LRANGE (first 300 elements): 17064.85 requests per second
LRANGE (first 450 elements): 13661.20 requests per second
LRANGE (first 600 elements): 11074.20 requests per second
~ redis-benchmark -q -s /tmp/redis.sock
PING (inline): 80000.00 requests per second
PING: 82644.62 requests per second
MSET (10 keys): 41841.00 requests per second
SET: 72463.77 requests per second
GET: 81300.81 requests per second
INCR: 63694.27 requests per second
LPUSH: 70422.53 requests per second
LPOP: 80000.00 requests per second
SADD: 72463.77 requests per second
SPOP: 77519.38 requests per second
LPUSH (again, in order to bench LRANGE): 80645.16 requests per second
LRANGE (first 100 elements): 42372.88 requests per second
LRANGE (first 300 elements): 22779.04 requests per second
LRANGE (first 450 elements): 16891.89 requests per second
LRANGE (first 600 elements): 13458.95 requests per second
Resque (pronounced like “rescue”) is a Redis-backed library for creating background jobs, placing those jobs on multiple queues, and processing them later. It was written by GitHub and is used in production there, as well as on many other apps. Read their blog post: Introducing Resque
Vanity is an Experiment Driven Development framework for Rails that uses Redis. It allows you to define A/B tests in your Ruby on Rails application and integrates with Google Analytics via Garb.
Ohm is a library for storing objects in Redis, a persistent key-value database. It includes an extensible list of validations and has very good performance.
Rollout lets you roll out new features to select groups of users for testing. Rollout has been covered on the changelog. Also works in tandem with Degrade
Soulmate is a tool to help solve the common problem of developing a fast autocomplete feature. It uses Redis’s sorted sets to build an index of partially completed words and the corresponding top matching items.
Written by Redis creator, Salvatore Sanfilippo, and key contributor, Pieter Noordhuis, the Redis Book will show you how to work with different data structures, how to handle memory, replication, and the cache itself, and how to implement messaging, amongst other things! Buy the book
If you’ve ever wanted to know how many active or idle Passenger processes your server has and display them inside your app, you can use the following helper:
NGINX is an awesome server, but unfortunately contains an error in earlier versions (pre 0.8.32), that sends the incorrect headers for 201 (created) responses. It does not set the Content-Length header, which causes modern browsers to keep the connection open and wait until the timeout value is exceeded.
There are two possible fixes for this; Upgrade NGINX to version 0.8.32 or greater, or fix the issue in your server side code. I’ll show you how we can do the latter, using Rack.
Rack provides a minimal, modular and adaptable interface for developing web applications in Ruby. By wrapping HTTP requests and responses in the simplest way possible, it unifies and distills the API for web servers, web frameworks, and software in between (the so-called middleware) into a single method call.
We will use a piece of Rack middleware to set the correct headers for any 201 responses.
Copy the code below into lib/content_length_fix.rb:
Bullet is a rails plugin, written by Richard Huang (@flyerhzm), that helps to kill N+1 queries. It shows you where you should be using :include in your ActiveRecord calls. Bullet also informs you where you’re missing counter caches as well as warning you of any unused eager loading.
SlimScrooge is a plugin by Stephen Sykes (@sdsykes), that restricts the columns retrieved in your MySQL queries by learning which attributes are subsequently called on the ActiveRecord model.
Below is an example, taken from the readme:
# 1st request, sql is unchanged but columns accesses are recordedBrochureLoadSlimScrooged1sttime(27.1ms)SELECT*FROM`brochures`WHERE(expires_atISNULL)# 2nd request, only fetch columns that were used the first timeBrochureLoadSlimScrooged(4.5ms)SELECT`brochures`.expires_at,`brochures`.operator_id,`brochures`.idFROM`brochures`WHERE(expires_atISNULL)# 2nd request, later in code we need another column which causes a reload of all remaining columnsBrochureReloadSlimScrooged(0.6ms)`brochures`.name,`brochures`.comment,`brochures`.image_height,`brochures`.id,`brochures`.tel,`brochures`.long_comment,`brochures`.image_name,`brochures`.image_widthFROM`brochures`WHERE`brochures`.idIN('5646','5476','4562','3456','4567','7355')# 3rd requestBrochureLoadSlimScrooged(4.5ms)SELECT`brochures`.expires_at,`brochures`.operator_id,`brochures`.name,`brochures`.idFROM`brochures`WHERE(expires_atISNULL)
Query Reviewer by David Stevenson (@dsboulder) of Pivotal Labs, is a Rails plugin that adds a div to the top left of the screen that contains lots of useful details regarding the MySQL executed on the current page.
The plugin makes it easy to view the EXPLAIN output for each SELECT query on the page. It also provides ratings and warnings on each query executed on a page.
Rails Indexes will generate the example migration containing suggested indexes. While these indexes are a good start, you will probably find that you need some detailed database indexes.
Ambitious Query Indexer is an index generating plugin by Sam Phillips (@samsworldofno). Like Rails Indexes, it generates a migration containing suggested indexes, but it works by analysing all of the queries it can find in your app.
If you ever need to know if an image is portrait or landscape in orientation, you can do the following (assuming you have an orientation attribute on your model:
You know those times when Textmate beachballs for about 5 seconds when it regains focus, it’s generally caused by the fact you’ve got about 16 million folders in your public/system folder used by paperclip.
Here’s a quick tip to speed things up by ignoring those folders:
Open Textmate Preferences and goto the Advanced section. Then click on Folder References.
Note: MailStyle was originally called Shemail but was changed due to a general negative response to the name from the public.
Background
Writing inline styles for HTML emails is dull and boring but unfortunately a necessary evil. Rather than do it by hand we thought it would be nicer to let our app do it for us. So we wrote MailStyle.
Enter MailStyle
MailStyle allows you to write the css for your html emails as you normally would, then writes the styles inline when you send your emails. It also makes sure that your image paths are absolute rather than relative.
This will look for a css file called email.css in your public/stylesheets folder. The css method can take either a string or a symbol. You can also pass the css file name with or without the .css extension.
MailStyle will now write the styles from email.css into html part of the welcome email (eg. welcome_email.text.html.erb). It won’t touch the plain text part, neither will it do anything if you’re only sending a single part email (eg. welcome_email.html.erb). You shouldn’t be sending html emails without a plain text version anyway.
Say that our email.css file looks like the following:
Have you ever gotten a result like the following when using ThinkingSphinx (by the awesome Pat Allen):
NoMethodError(undefinedmethod`constantize' for nil:NilClass):
This error occurs when your index isn’t quite up to date and ThinkingSphinx returns results that have since been deleted from your database. To fix the problem add :retry_stale => true to your searches, like this:
Article.search('chunky bacon',:retry_stale=>true)
There is more information about :retry_stale in the source code:
# If you pass :retry_stale => true to a single-model search, missing records will# cause Thinking Sphinx to retry the query but excluding those records. Since search# is paginated, the new search could potentially include missing records as well, so by# default Thinking Sphinx will retry three times. Pass :retry_stale => 5 to retry five# times, and so on. If there are still missing ids on the last retry, they are# shown as nils.
I hope this saves someone a few minutes in the future :)
Those of you that follow me on Twitter will probably know that I’ve spent the last week or so trying to find a decent way of generating PDF documents from a Rails application. I finally found a solution that suited my needs so I thought I’d share it with you lovely people.
Initial Probing
After my first round of googling I came across 2 solutions that people seem to be using:
I’ll admit I didn’t really look too much into PDF::Writer but I did spend a couple of days playing around with Prawn.
All was going well until I ran into certain situations. The two main problems I had with Prawn were that it’s too difficult to style things as I wanted to and generating a table of contents. I might be missing something but I couldn’t get my head around how to solve the latter.
I don’t want to learn a new syntax to define my PDF documents. I don’t want to learn a new way of styling things. I like my HTML and CSS.
WHERE’S MY HTML AND CSS?!
Introducing Prince
Prince XML is a command line program that takes your spiffy html and css and returns a nicely formatted PDF document for you.
Prince is a computer program that converts XML and HTML into PDF documents. Prince can read many XML formats, including XHTML and SVG. Prince formats documents according to style sheets written in CSS.
See, I told you.
So, we’ve got prince xml, but what about hooking it up with rails?
Princely is basically a wrapper around the Prince API. It allows you to define your PDF views as templates like show.pdf.erb. You can write your views as you would normal html views and Princely will return a pdf when you hit those pages.
To set the page numbers of you PDFs you’ll need to use the counter attribute of CSS3.
@page{@bottom-left{content:counter(page);}}
This snippet of code will, funnily enough, add the current page number to the bottom left of each page. That’s all there is to it.
If you’d prefer to show the page number along with the total number of pages, you can use the following:
@page{@bottom-left{content:"Page "counter(page)" of "counter(pages);}}
Table of Contents
If you’re creating a large PDF with a few sections, it’s generally a good idea to include a table of contents at the start of your document.
The first thing you need to do, is output a list of links at the start of you document that link to internal anchors:
<ulid="toc"><li><ahref="#ruby">Chapter 1: An Introduction to Ruby</a></li><li><ahref="#rails">Chapter 2: Hello, Rails!</a></li><li><ahref="#prince">Chapter 3: Pump it up, Prince!</a></li></ul>
This will give you a list, that looks something along the lines of the following image:
Now with a bit of CSS magic, we can add the page numbers from our PDF to the table of contents. Ready for this? Go!
That’s it. attr(href) finds the target of the link. target-counter finds the page that the anchor is on and the leader call just pads the left had side with periods. Win.
That nifty bit of CSS should leave you with something looking like this:
Over the last few months I’ve realised that the speed at which I develop new projects is a lot quicker than it used to be. So I thought I’d share some of the things I’ve learned and also some quite obvious things (to me at least).
Use a Base Application
I’m obviously going to be horrifically biased due to the fact that I helped to develop Bort, but I think that base apps are the way to roll. They save you about half a days worth of development and let you get straight into developing your application rather than fucking around doing the same monotonous stuff every time.
So here’s a run down of base apps floating around:
Bort by myself and the rest of the Fudge development team
I haven’t used any of these apart from Bort, so I can’t really give you any opinion but everything I’ve seen by Thoughtbot and James Golick have always been awesome. Just look through them and find which one suits your needs.
The default Rails scaffold generator is alright for prototyping an app but let’s face it, you wouldn’t use it for everything. So why don’t you made your own that you can use for everything. At the start of the last project we worked on, we spent 2-3 days working on a scaffold generator that would help to generate parts of the admin.
We made the generator generate all the search stuff, add sortable tables, generate basic specs and a whole bunch of other awesome stuff. Now we can get an awesome admin section set up for a model by running line from terminal.
This must have saved us at least a weeks worth of time. Time that we can now spend making sure that the rest of the site is as brilliant as possible. With the extra time, you take it easy, or you could add extra features, improve the UI, whatever. Keep it RESTful, kids.
Use a Form Builder
I hate forms. No secret there. But alas, nearly every application you’ll develop need to have forms. I wrote a custom form builder for the chaps at Fudge and it saves us a hell of a lot of time.
Now instead of writing something like the following:
Now imagine you’re got to write close to 50 forms for an application. Can you guess which ones saves you time? Which one is more enjoyable to use? You got it.
Now while I wouldn’t say our form builder is ready for the general coding public (it isn’t), there are still a few out there.
I have used Semantic Form Builder by RubyPond before and it also happens to be the one we based out form builder on.
Build a Populate Rake Task
We started using Populator/Faker a couple of months a go and this is probably one of our biggest time savers. It’s a pain in the ass adding test data into your applications.
Ryan Bates has made a great railscast on how to use Populator along with Faker to generate fake datausing a rake task so I’ll leave it to his awesome video to tell you all about it.
There are also a couple other options out there for generating fake data, the random-data gem and the Forgery plugin.
This should really go without saying, but I’ve seen a few people trying to write (poor) code for tasks that have already been solved, tested and improved on.
Gems and plugins are probably your biggest time saver. One of the things I love about the ruby community is that a lot of people give back to it.
If you have a problem, have a look on the awesome GitHub and see if there’s a plugin/gem floating around that looks like it could solve your problem. Try it out. If it works brilliant, if not see if you can fix it and improve the original code. Then if someone else has the same problem, they can use the plugin. If everyone helps out, we all have an easier job, we can do less work and enjoy life more.
Seriously, Just Buy a Fucking Mac
Just do it. Stop making excuses. I was a Windows user for about ten years but mainly because I didn’t know any better. I now work full time on a mac, both at home and at work, and there’s not a thing you could do to make me go back to Windows.
Windows simply won’t do a lot of things that you’ll want to do. Background jobs? Not a chance. Git? oh yeah, you can use msysgit but who the fuck wants to open up a separate program just to use git? Fuck off Windows. You’re slow and you suck.
Why get a mac? Rails runs faster. You can use the best text editor around, TextMate. You can install all those gems and plugins that all say: “This won’t work on Windows”.
Think getting a mac is too expensive? Get a low spec mac mini for $599. That’s what I started using and even though it’s low spec I never had a problem with it. You can use your USB keyboard, mouse and your monitor from your Windows machine. Still think it’s too much? Have a look on Amazon…
So do you, my lovely readers, have any more suggestions/tips to speed up your development?
I probably should have done this sooner but I’ve finally got around to updating Bort to Rails 2.2
Here are some other changed.
Will_paginate, AASM, Rspec and Rspec-rails updated to gems
I’ve decided to remove the above plugins and unpack the most recent version into the vendor/gems directory. The main reason is its easier to keep track of which version you’re using and what needs updating. So Bort is currently rocking the most recent versions of those gems.
Exception Notifier Email Automatically Set to the Email Set in Settings.yml
This is something I thought we’d already done but alas not. Thanks to feedback on UserVoice for that one.
README Updated
The readme has been updated to let people know that they need to change the default admin password in the bort_migration along with the RESTFUL_AUTH_SITE_KEY in each of the environment files.
If you haven’t done this yet, make sure you do it yo.
Multistage Capistrano Deployment
Thanks for Phil Jeffs for fixing this one. Bort is now setup out of the box to deploy to a staging environment along with production.
Bort Sends a 404 on ActiveRecord::RecordNotFound
This is something that I normally forget to do in applications so it’s now baked into Bort. If a user requests a page and the record it’s looking for doesn’t exist, they’ll get sent to the 404 page with the correct status. If you don’t want this to happen, just remove the code from application.rb file.
Rake db:database_dump
Matt Hall has added a rake task to allow you to dump the contents of you database. Simply run rake db:database to get a dump of all the contents of your database.
Upcoming Suggested Changes
The two main upcoming changes to Bort are:
Default User Admin Panel
A lot of people seem to want this feature. We’re currently on the fence about it. Bort has tried to keep as simple as possible while keeping the features that a lot of us use. Thoughts on this would be great.
Add i18n support
Again a lot of people seem to want this but again we’re on the fence due to the reason above.
Removal of Role_requirement
I’ve noticed a lot of people on github who fork Bort seem to remove role_requirement. Also, I’ve found myself doing the same thing in favour of other options.
What do you guys think?
Suggestions? Problems?
As always, if you have any suggestions or problems then leave a message on our UserVoice and we’ll see what we can do.
I’ve integrated OpenID with RESTful Auth on Bort in the new version. I’ll be perfectly honest though, I’ve never actually set up OpenID before, so I’d appreciate if people could take a look at it and let me know if it sucks.
User Voice! Load Noises!
We’ve set up an account on User Voice so you guys can submit ideas and all that jazz to us, then we can act like power hungry sultans and deny your ideas.
When I set up a new rails app, I generally do the same things every time. Set up a config file, install RESTful authentication, add password recovery stuff, blah blah. I’m sick of doing the same stuff over and over again. Enter Bort.
Bort is a base application featuring all the things I set up with every application. Now I can just download the app from git and be up and running within a matter of minutes. POW!
For those of you wondering is Bort stands for anything like “Bionic Optical Radioactive Trout”, it doesn’t. It’s taken from this episode of The Simpsons:
Anyway, enough of this piffle, on to the features:
The Features
I’m going to copy and paste this jazz from the readme file because, quite frankly, I’m lazy.
RESTful Authentication
RESTful Authentication is already setup. The routes are setup, along with the mailers and observers. Forgotten password comes setup, so you donÃt have to mess around setting it up with every project.
The AASM plugin comes pre-installed. RESTful Authentication is also setup to use user activation.
Will Paginate
We use will_paginate in pretty much every project we use, so Bort comes with it pre-installed.
Rspec & Rspec-rails
You should be testing your code, so Bort comes with Rspec and Rspec-rails already installed so youÃre ready to roll.
Exception Notifier
You donÃt want your applications to crash and burn so Exception Notifier is already installed to let you know when everything goes to shit.
Asset Packager
Packages up your css/javascript so youÃre not sending 143 files down to the user at the same time. Reduces load times and saves you bandwidth.
Routes
The routes for RESful Auth and the forgot password stuff are already sorted for you.
Settings YAML
There is a settings.yml file that contains site-wide stuff. The site name, url and admin email are all used in the RESTful Auth mailers, so you donÃt need to worry about editing them.
Database YAML
The database.yml defaults to sqlite3 but also contains the settings for MySQL in comments so you can switch over easily.
Capistrano Recipe
Bort comes ready to rock capistrano. The recipe that is setup is based on using git and passenger. Edit as you see fit.
Uses the Database for Sessions
Bort is setup to use the database to store sessions by default.
Misc
password and password_confirmation are set up to be filtered
there is a default application layout file
a page title helper has been added
index.html is already deleted
rails.png is already deleted
a few changes have been made to the default views
Using Bort
The git repo is located here: http://github.com/fudgestudios/bort/tree/master
Edit: The code has been updated due to the awesome information presented in the comments.
For a project we’ve been working recently, we had to create four (uurgh) models from one form. After a lot of digging around and some trial and error we came up with a method which works well for us. I thought I’d document it for others as I couldn’t find a lot about it when originally trying do it.
Background
Say we have 3 models that are all mutually exculise from each other but we need to make sure that all of the models are valid before we save them. The original pplan was to use something similiar to the following:
The problem with this method is: if @person and @dog are valid and save correctly but @dog fails due to validation, then you end up with a person and cat in your database when you don’t want them. This leads to infinite amounts of problems, as rSpec has happily announced on more than one occassion.
The second thing I tried was checking that all the models are valid first then saving them:
While this looks good on the controller side, it actually sucks. If person is invalid then the errors are shown on the page as expected, but you don’t to see if any of the other models have any errors because valid? doesn’t get called on them. Aaargh!
The Solution
The View
Did you know you could pass in more than one model to error_messages_for? No, neither did I? What about fields_for? It’s a life saver. Let’s look at an example form for a Person, Cat and a Dog:
The main things to look out for here are error_messages_for and fields_for. We pass in an array of the objects we want to display errors for into error_messages_for using :object. This will display all the errors for those models, in our case the person cat and dog errors. Although you need to make sure all the errors for these models are being raised. We’ll look at this later on.
The other thing to take a look at is fields_for. I’ll let the API docs explain this for you:
Creates a scope around a specific model object like form_for, but doesnët create the form tags themselves. This makes fields_for suitable for specifying additional model objects in the same form.
So that’s our views done. On to the controller:
The Controller
This is the way we’ve been coping with the problem of validating all the models. I’m sure other people will have other suggestions, but this is what we’re rocking:
defnew@person=Person.new@cat=Cat.new@dog=Dog.newenddefcreate@person=Person.new(params[:person])@cat=Cat.new(params[:cat])@dog=Dog.new(params[:dog])# Run valid? on each model and check for failuresif[@person,@cat,@dog].all?(&:valid?)Person.transactiondo@person.save!@cat.save!@dog.save!endelse // Epic fail endend
The only line that you really need to checkout here is the line that runs valid? on each model and check results:
if[@person,@cat,@dog].all?(&:valid?)
This line runs through each model and runs the valid? method and checks that all the results are true.
As pointed out in the comments, this line could be replaced with:
if@person.valid?&@cat.valid?&@dog.valid?
The Person.transaction block makes sure that if one of the models fails to save then the other models aren’t saved as well. This stops you ending up with random saved models that shouldn’t be there.
By default, Rails comes packed with the Prototype javascript library and the effects library, Scriptaculous. While this is all well and good sometimes you want a change. I personally prefer jQuery to prototype. I don’t have any beef with prototype, infact I used it for about a year before even getting into rails, but I just prefer the jQuery syntax and selectors.
jQuery
jQuery is a fast, concise, JavaScript Library that simplifies how you traverse HTML documents, handle events, perform animations, and add Ajax interactions to your web pages. jQuery is designed to change the way that you write JavaScript.
jQuery, like Protoype, is a javascript library that takes care of much of the grunt work you face day to day. It helps to resolve your cross browser issues, makes creating dom elements easier and various other things.
Some Prototype / jQuery Examples
I’ll post a couple of code examples so you can see the difference in the libraries. I’m not saying these examples are the best way to do things (I know people will say otherwise), they’re just here to help you understand the libraries.
Note: I haven’t tested these examples, although I believe they should all work.
Open all links marked with rel=”external” in new windows
For more information on jQuery syntax and all the bells and whistles, have a look at the jQuery Documentation.
More Prototype <=> jQuery Examples
Remy Sharp has also published a walk through comparison between Prototype and jQuery to help developers go from one language to another.
Hello, jRails!
Want to use jQuery but love your prototype helpers too much? Fear not! Enter jRails, stage left.
jRails is a drop-in jQuery replacement for Prototype/script.aculo.us on Rails. Using jRails, you can get all of the same default Rails helpers for javascript functionality using the lighter jQuery library.
Bosh. All sorted. The plugin will install all the required javascript files over to public/javascripts. Unless you’re planning on using prototype along side jQuery you will probably want to delete the prototype files in your javascripts folder.
Including jQuery and Friends
Now you want to open up your application.html.erb file and edit the javascript include tag:
<%=javascript_include_tag:defaults%>
This will now include all the jRails files instead of the prototype/script.aculo.us files. You might want to just include the files that you need instead of all these:
You don’t have to do anything. Brilliant. That’s the main point of the jRails plugin. It does all the grunt work for you. Just use your helpers as you normally would.
I will say one thing though: a lot of the time you may just find it easier to use page << at certain times:
page<<"$('span#bacon').text('CHunKy');"
jQuery UI
jQuery UI provides abstractions for low-level interaction and high-level, themeable widgets, built on top of the jQuery JavaScript Library, that you can use to build highly interactive web applications.
The core of the library revolves around different mouse interactions, namely drag and dropping, sorting, selecting, and resizing, as well as a powerful set of effects.
On top of the core interactions are built a number of reusable widgets, including accordions, date pickers, dialogs, sliders and tabs.
I was going to write some blurb about jQuery UI but I feel that this quote says it all, really. Want to know more? Check out the jQuery UI site
Some jQuery Scripts
I thought I’d list a couple of helpful scripts to help you on your way to the wonderful world of jQuery. So here goes:
jQuery lightBox plugin is simple, elegant, unobtrusive, no need extra markup and is used to overlay images on the current page through the power and flexibility of jQuery¥s selector.
lightBox is a plugin for jQuery. It was inspired in Lightbox JS by Lokesh Dhakar.
The better way to know what is jQuery lightBox plugin, click the Example tab above and see it in action.
Everybody loves a lightbox, surely? The jQuery Lightbox script is based on by Leandro Vieira Pinho.
If you have any other suggestions for great jQuery scripts, let me know and I’ll add them to the list.
So you’ve installed FFMPEG. Now it’s time to move onto converting the video. For this we’re going to be using a couple of plugins.
Paperclip
We will be using the paperclip plugin to upload the videos onto our server. Details of how to install paperclip can be found in my previous article: Paperclip: Attaching Files in Rails. To install you can use any of the following:
git://github.com/thoughtbot/paperclip.git # Github
https://svn.thoughtbot.com/plugins/paperclip/trunk/ # SVN
http://rubyforge.org/projects/paperclip/ # Gem version
Acts As State Machine
Acts_as_state_machine allows you to turn your model into a Finite State Machine (FSM).
A finite state machine (FSM) or finite state automaton (plural: automata) or simply a state machine, is a model of behaviour composed of a finite number of states, transitions between those states, and actions. A finite state machine is an abstract model of a machine with a primitive internal memory.
Nothing spectacular. If you’ve used Paperclip before then nothing should surprise you here. The has_attached_file :source line tells our model that it has an uploaded file called source. This is where we will be storing our video files. The rest of the file uses the built in Paperclip validations.
Adding States
Underneath your current model content, we want to add the following:
# Acts as State Machine# http://elitists.textdriven.com/svn/plugins/acts_as_state_machineacts_as_state_machine:initial=>:pendingstate:pendingstate:convertingstate:converted,:enter=>:set_new_filenamestate:errorevent:convertdotransitions:from=>:pending,:to=>:convertingendevent:converteddotransitions:from=>:converting,:to=>:convertedendevent:faileddotransitions:from=>:converting,:to=>:errorend
This will setup acts_as_state_machine along with the states and transitions we want to use. It’s all pretty simple.
Run the Migrations
Open up the xxx_create_videos.rb migration file and edit it so it looks like the following:
The columns starting with :source_ are all files for Paperclip. The :state column is used with acts_as_state_machine.
Run the migrations:
rake db:migrate
Adding the Conversion Methods
In your video.rb file add the following methods to your model. These methods take care of the converting the video file:
# This method is called from the controller and takes care of the convertingdefconvertself.convert!success=system(convert_command)ifsuccess&&$?.exitstatus==0self.converted!elseself.failure!endendprotected# This method creates the ffmpeg command that we'll be usingdefconvert_commandflv=File.join(File.dirname(source.path),"#{id}.flv")File.open(flv,'w')command=<<-end_command ffmpeg -i #{ source.path } -ar 22050 -ab 32 -acodec mp3 -s 480x360 -vcodec flv -r 25 -qscale 8 -f flv -y #{ flv } end_commandcommand.gsub!(/\s+/," ")end# This update the stored filename with the new flash video filedefset_new_filenameupdate_attribute(:source_file_name,"#{id}.flv")end
The Controller
I’m not going to post the views in this article as they should be straight forward. Just make sure to add :multipart => true to your form otherwise your file’s won’t be uploaded and you’ll look stupid.
classVideosController<ApplicationControllerdefindex@videos=Video.find:allenddefnew@video=Video.newenddefcreate@video=Video.new(params[:video])if@video.save@video.convertflash[:notice]='Video has been uploaded'redirect_to:action=>'index'elserender:action=>'new'endenddefshow@video=Video.find(params[:id])endend
After the video is saved in the create method, the convert method is called. This should convert the video to a flash video file, update the database entry and set the state of the model. The state will be set to converted if everything went to plan, or error if everything went to shit.
When you want to display the video in a view, you will need two things. The first, is swfobject, an unobtrusive way to include flash into a page.
SWFObject is a small Javascript file used for embedding Adobe Flash content. The script can detect the Flash plug-in in all major web browsers (on Mac and PC) and is designed to make embedding Flash movies as easy as possible. It is also very search engine friendly, degrades gracefully, can be used in valid HTML and XHTML 1.0 documents, and is forward compatible, so it should work for years to come.
The JW FLV Media Player (built with Adobe’s Flash) is an easy and flexible way to add video and audio to your website. It supports playback of any format the Adobe Flash Player can handle (FLV, but also MP3, H264, SWF, JPG, PNG and GIF). It also supports RTMP and HTTP (Lighttpd) streaming, RSS, XSPF and ASX playlists, a wide range of flashvars (variables), an extensive javascript API and accessibility features.
Make sure you include the swfobject.js file on the page you wish to display your video on:
<%=javascript_include_tag'swfobject'%>
Next, copy the mediaplayer.swf to public/flash/mediaplayer.swf
<divid="player">
You need to have <%= link_to 'Flash Player', 'http://www.adobe.com/shockwave/download/download.cgi?P1_Prod_Version=ShockwaveFlash' %> installed to display this video
</div><script type="text/javascript">varso=newSWFObject('/flash/mediaplayer.swf','mpl','480','360','8');so.addParam('allowscriptaccess','always');so.addParam('allowfullscreen','true');so.addVariable('height','360');so.addVariable('width','480');so.addVariable('file','<%= @video.source.url %>');so.write('player');</script>
The contents of the div will be replaced with the flash player, if flash isn’t installed the user is shown a message with a link to download flash player. The <%= @video.source.url %> line will output the path to the flv video file.
There’s a setup wizard on the JW FLV Player site located here.
Final Note
You shouldn’t really be converting videos with the user request. You should be using a background worker to do it for you. I’ll be showing you how to do this in the next article in this series.
Give it a whirl. As far as I know it should work fine. I’ve tested it on my local host and it seems to work. Admittedly, there should be a lot more error checking and whatnot, but for a simple example I think it does the job.
If you have any suggestions, improvements etc that I could incorporate into this article then leave a comment and I’ll sort it out.
This is the first of a three part series covering how to convert videos using the marvellous FFMPEG library. Video conversion is a must have if you are planning on creating a social network site.
In this part I’ll be covering how to install FFMPEG on Ubuntu Hardy Heron (8.04).
Install FFMPEG Dependencing
First off, you need to download and install the dependency packages for FFMPEG. Without these, it’ll all go tits. So it’s a good thing to sort out.
The lib* files help you to convert various video formats into flash videos, or which ever format you wish. Subversion is needed so you can download the FFMPEG source.
Check Out FFMPEG Source
Next, you need to checkout the current FFMPEG source from subversion. So let’s do that:
mkdir src
cd src
svn checkout svn://svn.mplayerhq.hu/ffmpeg/trunk ffmpeg
cd ffmpeg
Bosh! We now have the FFMPEG source on our server. So far so good.
Compiling FFMPEG
Now we’re ready to compile to beast. Make sure you’re in the ffmpeg directory that we just downloaded. Then run the configure command:
I love Phusion Passenger. It takes away most of the pain from deploying. Instead of having to mess around with lengthy apache config files, you can just upload. POW!
Phusion Passenger ó a.k.a. mod_rails makes deployment of applications built on the revolutionary Ruby on Rails web framework a breeze. It follows the usual Ruby on Rails conventions, such as ìDonÃt-Repeat-Yourself
Installing Passenger
Another great thing about Passenger is that it’s stupidly easy to install.
Then just follow the instructions that are displayed inside the terminal. It shouldn’t take more than 5-10 minutes max to get this shit on the road.
Passenger Meet Capistrano
You are using capistrano, aren’t you? Capistrano is a great tool, by Jamis Buck, for deploying your applications. It takes all the monotonous stuff and does it for you, which is nice.
If you’re not using capistrano, you can install it with the following:
geminstallcapistrano
Next, go to the root directory of your application and type:
capify.
This will set up your application for use with capistrano by creating a deploy.rb file and a Capfile. The deploy file is a recipe that will be used every time you deploy your application. Now lets look at making capistrano play with passenger.
The Deploy Recipe
I must confess something at this point: I’ve not actually tested this recipe yet as I’ve not had time. As far as I’m concerned it should work. If you find any problems let me know and I’ll fix them.
From what I’ve read, the last few lines are all you should need to restart your application. This will be called after all deploy calls so you shouldn’t have to worry about anything.
Long live passenger
Some Stuff to Read
Here’s a list of a few things that are worth reading regarding capistrano and/or passenger.
I’m not going to cover how to actually code an entire social network site in rails as all social network sites vary in their functionality (and it’ll take too long). I will cover plugins and other things you might find useful though.
Quick Start
If you don’t really want to do the coding but want to get a site up and running and soon as possible, you may want to have a look at Lovd by Less by the guys over at Less Everything. Lovd by Less contains user signups, galleries, blogs, comments and various other things that you might want, so it’s a great starting block for your site.
Social Network Plugins
Here’s a list of plugins that I’ve found to be useful while coding my own social networking site:
RESTful Authentication is pretty much the defacto standard for user authentication in rails. It allows easily set up user signups, login functionality and email notifications. The plugin doesn’t set up thing’s like forgotten password functionality but there is a great tutorial over Rails Forum.
# To Installrubyscript/pluginsourcehttp://svn.techno-weenie.net/projects/pluginsrubyscript/plugininstallrestful_authentication
Paperclip is a brilliant plugin by Jon Yurek over at ThoughtBot. Paperclip is used for managing file uploads and attaching the files to models. You can read more over at my article: Paperclip: Attaching Files in Rails.
# To Installsvnexporthttps://svn.thoughtbot.com/plugins/paperclip/tags/rel_2-0-2pistonimporthttps://svn.thoughtbot.com/plugins/paperclip/trunk
Acts_as_slugable takes the pain out of generating URL slugs. Everyone prefers meaningful URLs, so instead of showing a users page with ‘/users/231’, you can use ‘/users/jim-neath’. Nice.
# To Installrubyscript/plugininstallhttp://code.dunae.ca/acts_as_slugable
White_list is yet another brilliant from Techno Weenie. The white_list helper will html encode all tags and strip all attributes that aren’t specifically allowed. It also strips href/src tags with invalid protocols, like javascript: especially. It does its best to counter any tricks that hackers may use, like throwing in unicode/ascii/hex values to get past the javascript: filters.
# To Installrubyscript/plugininstallhttp://svn.techno-weenie.net/projects/plugins/white_list/
Fucking captchas. Unfortunately a necessary evil. If you’re going to use captchas then you might as well help to digitalise books. The reCAPTCHA plugin utilises the reCAPTCHA service which digitalises books by making users input the text.
# To Installrubyscript/plugininstallsvn.ambethia.com/pub/rails/plugins/recaptcha/
Everybody loves tagging, surely? Tag pictures, videos, blog posts, whatever you want. Acts_as_taggable_on_steroids is a great plugin for allowing your users to tag their stuff. It allows tag clouds and all that web 2.0 jazz everyone seems to love.
# To Installrubyscript/plugininstallhttp://svn.viney.net.nz/things/rails/plugins/acts_as_taggable_on_steroids
Exception Notifier is a must have. It emails you when your live application fails. No matter how much testing you do, no doubt there’s going to be a scenario where it fails and when that happens you want to know.
# To Installrubyscript/plugininstallexception_notification
This is one of my favourite plugins. Say your site get’s slashdotted of dugg and you end up with immense traffic, the main thing is to keep your site up and running. This is where throttler comes in. You can throttle certain actions on your site when your server load is above a certain level. So you could disable video uploads while your server load is above x to prevent your server from crumbling.
# To Installrubyscript/plugininstallhttp://svn.kabisa.nl/rails/plugins/throttler
You’ve been working on your social network site for months and finally the traffic is coming in and you have a decent user base. Then one day your server dies and you lose all your data. Woe is you. You should have backed up. Using Backup_fu you can automatically backup your database and files to Amazon S3.
# To Installsudogeminstallaws-s3rubyscript/plugininstallhttp://backup-fu.googlecode.com/svn/backup_fu/
Fischy_friends is a plugin by Daniel Fischer. It’s a great starting point for a friends system. I’ve used it on a couple of my own projects and it’s worked great for me.
I love SWFUpload. It uses a small flash file to allow users to upload multiple files at once. The front end is completely open and coded in javascript so you can customise it how you like. You can see the demos here.
TinyMCE is WYSIWYG editor coded entirely in javascript. It’s useful for the less techno savvy of your users (which will no doubt be most). There’s a whole load of plugins available for the editor so it’s highly extensible.
FFMPEG is a command line utility to convert various formats of video into other formats. The main use you’ll want to use this for is to convert videos into flv files for use with a flash video player.
The JW FLV Media Player (built with Adobe’s Flash) is an easy and flexible way to add video and audio to your website. It supports playback of any format the Adobe Flash Player can handle (FLV, but also MP3, H264, SWF, JPG, PNG and GIF). It also supports RTMP and HTTP (Lighttpd) streaming, RSS, XSPF and ASX playlists, a wide range of flashvars (variables), an extensive javascript API and accessibility features.
Rails Hosting
Once you’ve got your wonderful social network finished, you’re going to want somewhere to host the beast.
I highly recommend checking out Brightbox for all your hosting needs. They offer affordable servers complete with Five Runs.
Paperclip is an awesome rails plugin by Jon Yurek at Thoughtbot. It is one of many plugins currently available that cater for file uploading and thumbnailing (see: Attachment_fu, file_column, etc). Now a quick quote from Jon:
For some reason, file attachment is annoying. I don’t know why, and I know a lot of people have attempted to solve the problem in the past, myself included. Yet it still is. Having gotten fed up with gotchas and design decisions that we didn’t agree with, I went and wrote Paperclip on the plane to RailsConf last year. We’ve been using it here in various forms since and IMHO it’s the way to handle uploads, and finally decided that it should be released.
Installing Paperclip
You can install Paperclip using a variety of different methods:
Quick Note: If you’re a windows user, you’re going to need to go for the trunk version as this contains a fix to a problem that basically meant that Paperclip borked.
Attached files don’t need to have a separate model (thank god). Your attachments are treated just like any other attribute. Images aren’t saved until your model is saved. There are a lot of bonus options but I’ll cover them towards the end of the article.
classAddPhotoToUser<ActiveRecord::Migrationdefself.upadd_column:users,:photo_file_name,:string# Original filenameadd_column:users,:photo_content_type,:string# Mime typeadd_column:users,:photo_file_size,:integer# File size in bytesenddefself.downremove_column:users,:photo_file_nameremove_column:users,:photo_content_typeremove_column:users,:photo_file_sizeendend
Don’t forget to add these columns! Otherwise you’ll end up scratching your head and wondering where the hell you went wrong. The first part of the column names is the same as whatever you’re called your attached file. In our case that’s photo. Now update your database:
rake db:migrate
Now that your database is sorted, we can start working on adding some content. In your view you can add a file field like you would normally:
<% form_for :user,:html=>{:multipart=>true}do|f|%> <%= f.file_field :photo%><% end %>
Don’t forget the :multipart => true part or everything will fail. Then you will cry.
Now in your controller, you don’t need to do a thing (hooray).
defcreate@user=User.create(params[:user])end
You should now be able to upload user photos to your hearts content.
To display your user’s photos all you need to do is call:
Using :url you set when your images can be accessed from. The above setting would mean that your files are located at URLs similiar to /user/photo/1/thumb_originalfilename.jpg
The :default_url option is used if there is no attached file for a model. If a user doesn’t have any uploaded avatar you could use this option to set a default avatar to show.
:styles is a hash of thumbnail styles. The styles use the standard ImageMagick geometry rules. Paperclip also adds the ’#’ option which will create square thumbnails that are nicely cropped.
has_attached_file:photo,:default_style=>:thumb
:default_style is pretty straight forward. You can select a default style from your style list that will be called, instead of the original file, when you use @user.photo.url
Using :path you can select where the files are saved to on your box. If you change this, make sure to change the :url setting to relate to the new path.
has_attached_file:photo,:whiny_thumbnails=>true
:whiny_thumbnails will raise an error if there is a problem creating thumbnails. Set to true by default.
Some Waffle
Paperclip is a great plugin. It has a smaller memory footprint than Attachment_fu, it doesn’t require the use of Rmagick (eugh) and it has all the options that I’ve wished that Attachment_fu had. Give it a try and let me know what you think
Again, maximum kudos to Jon Yurek and all the guys over at ThoughtBot.