16
Jul 10

Announcing ShortService: A way to shorten URLs with any service

After using Twitter clients like TweetDeck and Seesmic I was wondering about the fact that every client has to implement every short-URL service (like TinyURL and bit.ly) they want. Why not make a service that functions as an interface between the client and the short-URL service. Then the client would only need to implement the interface.

This is what I’ve done with ShortService – a way to shorten URLs with any service.

At the time of writing, I’ve implemented 14 short-URL services, so you won’t have to. Just implement the easy to use API. Or use the service by hand.

ShortService is built on top of the Shortie gem – a RubyGem I’ve created so you can push your own shorteners.


09
Jul 10

Mass-assigning protected attributes in Rails

Rails has a great feature called protected attributes which you can set like this:

class User < ActiveRecord:Base
  attr_protected :account_id
end

Or you can use the inverted versions (which I prefer) where you set which attributes are accessible, like this:

attr_accessible :name, :email

What this does is that it tells Rails which attributes can be used in mass-assignment like this:

User.create(:name => "Lasse", :email => "lassebunk@gmail.com")

or what’s used more:

User.create(params[:user])

Then some malicious hacker cannot use mass-assignment to manually set the account_id.

If you try to assign to protected attributes you’ll get the following warning:

WARNING: Can't mass-assign these protected attributes: account_id

But the problem is: What if I’m no hacker, but I should have unlimited access, for example as an administrator? Then I can’t mass-assign to any protected attributes. Then I’d need to do something like this:

u = User.new(params[:user])
u.account_id = params[:user][:account_id]

Not very pretty.

What I’ve done is that I’ve created an extension to some of the methods taking mass-assignment and added an optional parameter called guard_protected_attributes which has a default value of true.

Example:

# config/initializers/unprotected_attributes.rb
class ActiveRecord::Base
  def update_attributes_with_unprotected(attributes, guard_protected_attributes = true)
    send :attributes=, attributes, guard_protected_attributes
    save
  end
  alias_method_chain :update_attributes, :unprotected
end

We can do this because the native ActiveRecord::Base#attributes= can also be called with guard_unprotected_attributes.

Now you can call update_attributes like this:

user = User.find(3)
user.update_attributes(params[:user], false)

and it will also assign the protected attributes.

I have made extensions to create, new, update_attributes, and update_attributes!.

The ugly part, however, is that to make it work, I had to copy the functions in their entirety which could potentially mean that if you use it on a Rails version other than exactly 2.3.8 it might not work. Sorry for that.

You can download the extensions here.


02
Jul 10

My first Linux server: Uptime: 365 days

This post is to announce that my first Linux server has now officially been up for a whole year!

21:03:57 up 365 days, 21:53,  2 users,  load average: 0.00, 0.00, 0.00

I originally used this server as a staging server but later on cancelled my Slicehost virtual server and began using my own server as a production server. It now hosts lassebunk.dk, tweetmycam.com, and userdriven.dk.


13
Mar 10

How to run multiple sites on OS X using Apache

Update 1: An automated way doing all the stuff in this post is using VirtualHostX – you might want to try that out. It’s free for up to three vhosts – after that it costs money.

Update 2: Or even better: You can use the all free hostess. It’s pure command line and works great.

Today I wanted to test some PHP and MySQL using Apache in OS X but wasn’t able to find any guide on how to do this if I wanted multiple sites. So I might as well create my own:

cd /etc/apache2
sudo mkdir mysites
# or whatever (I used my name, 'lasse', for the name)

cd mysites
sudo nano phptest.conf
# or vi or whatever

Put the following in phptest.conf:

<VirtualHost *:80>
  ServerName phptest.local
  DocumentRoot "/Users/yourname/dev/web/phptest"
  <Directory "/Users/yourname/dev/web/phptest">
    Order allow,deny
    Allow from all
  </Directory>
</VirtualHost>

Remember to replace yourname for your username and to create the ~/dev/web/phptest folder.

Back into the bash:

cd /etc/apache2
sudo nano httpd.conf

First find the lines that say:

#LoadModule php5_module        libexec/apache2/libphp5.so
#LoadModule fastcgi_module     libexec/apache2/mod_fastcgi.so

And uncomment these two lines likes this:

LoadModule php5_module        libexec/apache2/libphp5.so
LoadModule fastcgi_module     libexec/apache2/mod_fastcgi.so

This enables PHP.
Next, go to the bottom of the same file and add the following line:

Include /private/etc/apache2/mysites/*.conf

This tells Apache to also load configuration files from the mysites folder.
Next, edit your hosts file to enable the phptest.local name:

sudo nano /etc/hosts

Add the following line at the bottom of the file:

127.0.0.1 phptest.local

This tells your DNS resolver to look for the site locally at your computer (127.0.0.1) when you type phptest.local in your browser.

It’s necessary to restart Apache to enable the new settings (you’ll need to do this every time you add a site).

sudo apachectl -k restart

Finally we create a test file to make sure it all works:

cd ~/dev/web/phptest
nano test.php

Enter the following:

<?php echo "Hello World!" ?>

Now you should be able to go to http://phptest.local/test.php in your browser and it should say Hello World!. If not, then something is wrong.

Adding a new site

Next time you want to add a site, just complete the following steps:
1. Create a site root folder in ~/dev/web/xx or wherever you keep your sites.
2. Create a configuration file similar to phptest.conf in /etc/apache2/mysites/ where you replace the paths and ServerName for the new ones.
3. Create an entry in /etc/hosts with the same name as you used as ServerName.
4. Restart Apache using apachectl -k restart.

Is there an easier way to do this? Please let me know in the comments.


05
Mar 10

Outputting the flash to views and layouts

Here is a simple way of outputting the first message in the flash (because I didn’t want it to output both flash[:error] and flash[:notice] at the same time).

# in the controller
flash[:notice] = "Thanks for signing up!"

.. and…

# in the view
<% flash.detect do |type, text| %>
	<div id="flash" class="<%= type.to_s %>">
		<%= text %>
	</div>
<% end %>

The detect method will return the first key/value pair of the flash where the block doesn’t return false. However, that’s not what we’re using it for – we’re using it to make sure we only get the first element.

Hope this is useful.


25
Feb 10

Using Sinatra to serve smaller (than Rails) applications

So, maybe you’ve been coding Rails for a while and wondered – “do I really need this full stack framework to serve even small applications?”. Well, no you don’t :-)

Check out Norbauer’s DNS Tools (and on Github). It’s a small set of easy to use DNS tools. So small it would be overkill to serve it using Rails.

Norbauer’s using Sinatra to serve the app.

Start by installing the gem:

$ sudo gem install sinatra

After that it’s as simple as this:

# myapp.rb
require 'rubygems'
require 'sinatra'

get '/' do
  "Welcome to my homepage!"
end

get '/contact' do
  "My contact info is..."
end

At your terminal:

$ ruby myapp.rb
== Sinatra/0.9.4 has taken the stage on 4567 for development with backup from Mongrel

Now you can view it in your browser at http://localhost:4567 and http://localhost:4567/contact. Simple.

This is great for hosting apps from your command line (for example check out Taps) but what if you wanted to serve it like you would a Rails app?

Well, then you’d be using Rack.

Create a file named config.ru in the same folder as myapp.rb:

require 'myapp'
run Sinatra::Application

Now you can deploy your application as you would if it was written in Rails (thanks to config.ru).
If you want to check this setup at your localhost, run the following:

$ sudo gem install rack # make sure you have Rack installed
$ rackup # run the Rack application using config.ru

It’s as easy as that! Great for hosting small applications.

Also see:


18
Feb 10

Using Paperclip and jpegcam to get pictures from your webcam into Rails

Here’s how to get pictures from your webcam into Rails using the Paperclip plugin and jpegcam.

What we will do is create a Photo model and a Photos controller with actions new, upload and create to take care of the image creation.

Start by creating a new Rails application:

$ rails webcam_app
$ cd webcam_app

Create the Photo model:

$ script/generate model Photo description:string
$ rake db:migrate

Create the Photos controller:

$ script/generate controller Photos

Edit config/routes.rb to contain a photos resource:

map.resources :photos, :only => [:index, :show, :new, :create], :new => { :upload => :post }

Download jpegcam and put webcam.js in your public/javascripts folder and webcam.swf and shutter.mp3 in your public folder.

Create the layout file app/views/layouts/application.html.erb and insert the following HTML:

<html>
  <head>
    <%= javascript_include_tag :defaults %>
    <%= javascript_include_tag 'webcam' %>
  </head>
  <body>
	  <%= yield %>
  </body>
</html>

Next, create app/views/photos/new.html.erb and make a div for the webcam contents:

<div id="webcam"></div>

And the actual webcam javascript:

<script type="text/javascript">
  webcam.set_swf_url('/webcam.swf');
  webcam.set_api_url('<%= upload_new_photo_path %>');
  webcam.set_quality(90);
  webcam.set_shutter_sound(true, '/shutter.mp3');
  $('webcam').innerHTML = webcam.get_html(640, 480);
</script>

That will run the actual webcam so you can see yourself :) But for taking a picture, we’ll need to add the following button:

<input type="button" value="Take picture" onclick="webcam.snap();" />

Now when you click the button, the webcam image will be posted to /photos/new/upload. Try it out:

$ script/server

and go to http://localhost:3000/photos/new.

Let’s add some code for handling the upload.

The webcam.swf just uploads a bunch of jpeg data so we’ll need to get a hold of the raw post data. That’s done with Rails’ request.raw_post. In your PhotosController:

def upload
  File.open(upload_path, 'w') do |f|
    f.write request.raw_post
  end
  render :text => "ok"
end

private

def upload_path # is used in upload and create
  file_name = session[:session_id].to_s + '.jpg'
  File.join(RAILS_ROOT, 'public', 'uploads', file_name)
end

Remember to create the public/uploads folder.

Now, back to app/views/photos/new.html.erb. Create the following at the bottom of the view:

<% form_for Photo.new, :html => { :style => "display: none;" } do |f| %>
  <p>
    <%= f.label :description %><br />
    <%= f.text_field :description %>
  </p>
  <p>
    <%= f.submit "Save the photo" %>
    or <%= link_to "Take another", new_photo_path %>
  </p>
<% end %>

In your javascript just below the webcam div, insert the following function:

function upload_complete(msg) {
  if (msg == 'ok') {
    $('new_photo').show();
    $('photo_description').focus();
  } else {
    alert('An error occured');
    webcam.reset();
  }
}

And add the following webcam code:

webcam.set_hook('onComplete', 'upload_complete');

Now when you take a picture you will get a new photo form for entering a description. If something goes wrong, the webcam will be reset so you can try again. This might also be a good time to check your logs.

Now we have the upload (see for yourself in your public/uploads folder) but we still need to add Paperclip to the model.
Start by installing the plugin:

$ script/plugin install git://github.com/thoughtbot/paperclip.git

In the Photo model:

class Photo < ActiveRecord::Base
  has_attached_file :image, :styles => { :medium => "300x300>", :thumb => "100x100>" }
end

For this to work, we need to add some necessary Paperclip columns to our Photo model:

$ script/generate paperclip photo image
$ rake db:migrate

Now we can show photos like this:

<%= image_tag photo.image.url(:thumb) %>

We just need to save the photos first. Add the following to your PhotosController somewhere above the private keyword:

def create
  @photo = Photo.new(params[:photo])
  @photo.image = File.new(upload_path)
  @photo.save

  redirect_to @photo
end

def show
  @photo = Photo.find(params[:id])
end

def index
  @photos = Photo.all
end

In app/views/photos/show.html.erb:

<h1>Photo</h1>
<p><%= image_tag @photo.image.url(:medium) %></p>
<p>
  <strong>Description:</strong><br />
  <%=h @photo.description %>
</p>
<p>
  <%= link_to "Take a new picture", new_photo_path %>
  | <%= link_to "See all pictures", photos_path %>
</p>

And last but not least in app/views/photos/index.html.erb:

<h1>All photos</h1>
<p>
  <% @photos.each do |photo| %>
    <%= link_to image_tag(photo.image.url(:thumb)), photo %>
  <% end %>
</p>
<p>
  <%= link_to "Take a new picture", new_photo_path %>
</p>

Now start your script/server if it isn’t already, go to http://localhost:3000/photos – aaannnd.. it works!


10
Oct 09

Streaming radio on iPhone or iPod Touch

I have found a really great little program called FStream that works for streaming M3U and PLS stations on the iPhone and iPod Touch.

FStream playing

The concept is that you add one or more radio stations. You can do it directly in the app or you can enable a web administration interface that works really great:

FStream web interface

I really like the application because it’s stable, and it simply does what it does; plays internet radio. Thanks SourceMac.

Check out FStream on iTunes


24
Sep 09

Three months on the Mac stack

It’s actually four months now – since May 1st – but I’ve been wanting to write this article for a month. Hence the – somewhat misleading – title.

I bought my MacBook on May 1th after viewing a screencast where a guy sets up a blog in 15 minutes using Ruby on Rails. I immediately said to my stepdad: “I’m going to buy a Mac and learn Ruby on Rails!”

And so I did – the day after, I bought a Mac.

I’ve always been a dedicated user of Microsoft’s products. First C64, then Amiga, then Mac, then PC. I liked the way everything was tested and came from one place, unlike open source. I’ve always been saying stuff like “I like to pay for my software because then I’m be sure about the quality.” – but in reality, everyone who uses Windows and other Microsoft products know that this isn’t always the case.

So I bought the Mac, and the first thing that surprised me, was how much of day-to-day work was done in the Terminal, or command line. When I installed Ruby on Rails, it was via command line; when I installed plugins, it was via command line. Evererything command line. :-)

Over the next few days I began to get a hang of it. I bought a couple of domain names and signed up for a slice at Slicehost – because I had read some job description that said that you should’ve at least tried to use a whole day of setting a slice.

Coming from Windows, Linux is a whole other deal to setup. I used a lot of the Slicehost articles that guides you through the whole process from setup and security to getting your slice to run as a webserver.

In the beginning I was a little nervous about all the command lines, if they would really work and so one. But the more you try it, the more calm you get. It just works! And lucky me there was a lot of helpful articles about Unix and Linux commands out there (just search for the command on Google).

Since starting out on the Mac, I’ve learned a multitude of things:

In short I’ve learned so much about the open source world that just wasn’t that easy on the Microsoft platform.

I still use Microsoft Windows and other products, but now it’s through VMware Fusion on the Mac.

I’m happy about the Mac because OS X is very unobtrusive, fast operating system and what it does, it does very good. But at the same time, I also want a netbook that’s easier to carry, so I may end up running both systems for different purposes (unless I’m just installing Ubuntu on the netbook too ;-)).

Hope you found this post interesting – I wrote it to tell about a beautiful (yak, I know) progress from Windows to Mac and Linux. Thumbs up if this has made you want to try it too. And please tell me in the comments. :-)


22
Sep 09

Launched Notesapp

I have just launched Notesapp which is an application for saving notes online – much like Delicious but with notes instead of links.

Hope you’ll try it – it’s at notesapp.net.

PS. I’ll expand the application to support various text formats and do an open API, but right now I just have other stuff to do. :-)


Fork me on GitHub