Quantcast
Channel: Lasse Bunk's weblog » jpegcam
Viewing all articles
Browse latest Browse all 2

Updated for Rails 3: Using Paperclip and jpegcam to get pictures from your webcam into Rails

$
0
0

View the complete source code for this post

Here’s how to get pictures from your webcam into Rails using the Paperclip plugin and jpegcam. It is an update of the Rails 2.3.x version of this post.

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 new webcam_app
$ cd webcam_app

Create the Photo model:

$ rails g model Photo description:string
$ rake db:migrate

Create the Photos controller:

$ rails g controller Photos

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

resources :photos, :only => [:index, :show, :new, :create] do
  post 'upload', :on => :collection
end

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

Edit the layout file app/views/layouts/application.html.erb and insert the following HTML inside the <head>-tag just below the other javascript_include_tag:

<%= javascript_include_tag 'webcam' %>

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_photos_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/upload. Try it out:

$ rails s

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 adding the plugin gem to your Gemfile:

gem 'paperclip', '~> 2.3'

Then run:

$ bundle install

to install the gem.

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:

$ rails g 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 rails s if it isn’t already, go to http://localhost:3000/photos – aaannnd.. it works!

View the complete source code for this post

Follow me on Twitter


Viewing all articles
Browse latest Browse all 2

Trending Articles