This is a post i made in my blog, i thought i'd post it here...

Photo galleries can be developed easily with Rails using the attachment_fu plugin. In this post i will give an example of how you could get started with this plugin, based on my own experience with it.

http://svn.techno-weenie.net/project...attachment_fu/

To use attachment_fu, you need to also choose an Image Processor, eg:

Rmagick
http://rmagick.rubyforge.org/

minimagick
http://rubyforge.org/projects/mini-magick/

image_science
http://seattlerb.rubyforge.org/ImageScience.html

I will be using Rmagick with ImageMagick (you need both).

"RMagick is an interface between the Ruby programming language and the ImageMagick and GraphicsMagick image processing libraries."

"ImageMagick is a software suite to create, edit, and compose bitmap images. It can read, convert and write images in a variety of formats (over 100) including DPX, EXR, GIF, JPEG, JPEG-2000, PDF, PhotoCD, PNG, Postscript, SVG, and TIFF. Use ImageMagick to translate, flip, mirror, rotate, scale, shear and transform images, adjust image colors, apply various special effects, or draw text, lines, polygons, ellipses and Bézier curves."

To install Rmagick + ImageMagick, follow the instructions in my previous post (this is for Windows users):

http://therailscoder.blogspot.com/20...agemagick.html

Now the rest of the code i display in this post presumes that you have already setup a User Model in your app, this is common to the popular authentication plugins, eg RESTful Authentication (which is what this example is based on). So, if you haven't got something like this, get it. I won't be going through REST or User Authentication in any depth at this point, but checkout this plugin if you want to continue:

http://svn.techno-weenie.net/project...uthentication/

Ok, so in this example we're going to have each User in your app have their own Photo Gallery. In the User's Photo 'index' view, we will see the thumbnail images of all the User's Photos. When you click on a thumbnail you will be directed to the User's Photo 'show' view to see the larger image. In this page you will see a description of the Photo, as well as an Edit and Delete link. When you Edit a Photo, you will be able to change it's description. A User can Edit and Delete only their own Photos. Of course, we will also need the form to upload the new Photo's. I hope that makes sense...

Right let's get started! The first step is to create a Photo resource which will give us our Photo Model and Photos Controller (amongst other things).

generate Photo resource

In the routes.rb file, you should already have a Users resource if you've setup RESTful Authentication correctly! Leave that as it is. We need to create a new nested resource. In the routes.rb file, so first delete the following line:

map.resources :photos

Replace it with this:

map.resources :users do |user|
user.resources :photos
end

This gives us access to urls such as:

users/1/photos/
users/1/photos/1
users/1/photos/1/edit
users/1/photos/new

THE MODEL

The relationship between User and Photos is a one-to-many relationship. That is, a User has many Photos, but a Photo belongs to just one User.

Add the 'has_many :photos' declaration at the top of your User Model.

class User
has_many :photos
end

Add the 'belongs_to :user' declaration in your Photo Model.

class Photo
belongs_to :user
end

Now add the 'has_attachment' declaration provided by the attachment_fu plugin. I have specified some basic options to keep file sizes under 2MB and to determine the exact size of the stored image files...

class Photo
belongs_to :user
has_attachment :content_type => :image,
:storage => :file_system,
:size => 0.megabyte..2.megabytes,
:resize_to => '450x450>',
:thumbnails => { :thumb => '150x150>' }
end

The has_attachment method has many more options, take a closer look at the README file that comes with attachment_fu for more info, below is an excerpt:

has_attachment(options = {})
This method accepts the options in a hash:

:content_type
# Allowed content types.
# Allows all by default. Use :image to allow all standard image types.

:min_size
# Minimum size allowed.
# 1 byte is the default.

:max_size
# Maximum size allowed.
# 1.megabyte is the default.

:size
# Range of sizes allowed.
# (1..1.megabyte) is the default. This overrides the :min_size and :max_size options.

:resize_to
# Used by RMagick to resize images.
# Pass either an array of width/height, or a geometry string.

:thumbnails
# Specifies a set of thumbnails to generate.
# This accepts a hash of filename suffixes and RMagick resizing options.
# This option need only be included if you want thumbnailing.

:thumbnail_class
# Set which model class to use for thumbnails.
# This current attachment class is used by default.

:path_prefix
# path to store the uploaded files.
# Uses public/#{table_name} by default for the filesystem, and just #{table_name} for the S3 backend.
# Setting this sets the :storage to :file_system.

:storage
# Specifies the storage system to use..
# Defaults to :db_file. Options are :file_system, :db_file, and :s3.

:processor
# Sets the image processor to use for resizing of the attached image.
# Options include ImageScience, Rmagick, and MiniMagick. Default is whatever is installed.

Examples:
has_attachment :max_size => 1.kilobyte
has_attachment :size => 1.megabyte..2.megabytes
has_attachment :content_type => 'application/pdf'
has_attachment :content_type => ['application/pdf', 'application/msword', 'text/plain']
has_attachment :content_type => :image, :resize_to => [50,50]
has_attachment :content_type => ['application/pdf', :image], :resize_to => 'x50'
has_attachment :thumbnails => { :thumb => [50, 50], :geometry => 'x50' }
has_attachment :storage => :file_system, :path_prefix => 'public/files'
has_attachment :storage => :file_system, :path_prefix => 'public/files',
:content_type => :image, :resize_to => [50,50]
has_attachment :storage => :file_system, :path_prefix => 'public/files',
:thumbnails => { :thumb => [50, 50], :geometry => 'x50' }
has_attachment :storage => :s3


The Photo Model needs to interact with the photos database table. So we need to create this table using a Rails migration. You should have a migration file for this that looks like:

00x_create_photos.rb

Edit or paste the code below into this file:

class CreatePhotos
def self.up
create_table :photos do |t|
t.column :parent_id, :integer
t.column :content_type, :string
t.column :filename, :string
t.column :thumbnail, :string
t.column :size, :integer
t.column :width, :integer
t.column :height, :integer
t.column :user_id, :integer
t.column :description, :text
end
end

def self.down
drop_table :photos
end
end

Migrations have changed a little in Rails 2.0, but the old migrations still work. The new way of doing things would look something like this:

class CreatePhotos
def self.up
create_table :photos do |t|
t.integer :parent_id, :user_id, :size, :width, :height
t.string :content_type, :filename, :thumbnail
t.text :description
end
end

def self.down
drop_table :photos
end
end

Now run the migration:

rake db:migrate

That should get the database side of things running.

THE CONTROLLER

Edit or paste the code below into photos_controller.rb:

class PhotosController
def index
@user = User.find(params[:user_id])
@photos = Photo.find(:all, :conditions => {:parent_id => nil, :user_id => @user})
end

def new
@photo = Photo.new
end

def create
@photo = Photo.new(params[:photo])
@photo.user = User.find(current_user)
if @photo.save
respond_to do |format|
flash[:notice] = 'Photo was successfully uploaded.'
format.html { redirect_to user_photos_path(current_user) }
end
else
render :action => :new
end
end

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

def edit
@user = User.find(current_user)
@photo = @user.photos.find(params[:id])
end

def update
@user = User.find(current_user)
@photo = @user.photos.find(params[:id])
if @photo.update_attributes(params[:photo])
respond_to do |format|
flash[:notice] = 'Photo was successfully updated.'
format.html { redirect_to user_photo_path(current_user, @photo) }
end
else
format.html { render :action => "edit" }
end
end

def destroy
@user = User.find(current_user)
@photo = @user.photos.find(params[:id])
@photo.destroy
respond_to do |format|
format.html { redirect_to user_photos_path(current_user) }
end
end
end

THE VIEW

Now let's work on the Photo view files.

The index.rhtml wil display all the thumbnails:

My Photos:
<&#37; @photos.each do |p| %>
<%= link_to image_tag(p.public_filename(:thumb)), user_photo_path(@user, p) %>
<% end %>

The show.rhtml will display the larger image, along with a description of the Photo, Edit and Delete links. The Edit and Delete links will only be displayed if the User is also the current & logged-in User. This will prevent one User from editing or deleting another User's Photos:

<%= @photo.description %>
<%= image_tag(@photo.public_filename) %>

<% if @user == current_user %>
<%= link_to 'EDIT', edit_user_photo_path(@user , @photo) %> |
<%= link_to 'DESTROY', user_photo_path(@user, @photo), :method => :delete, :confirm => 'Are you sure?' %>
<% end %>

The new.rhtml will display the file upload form:

Upload New Photo:
<%= error_messages_for :photo %>
<% form_for(:photo, :url => user_photos_path, :html => { :multipart => true }) do |f| %>
Select File: <%= f.file_field :uploaded_data %>
Description: <%= f.text_area :description %>
<%= submit_tag 'Upload Photo' %>
<% end %>

The edit.rhtml will contain a text_area field that will allow us to update the Photo description:

Edit Photo:
<%= error_messages_for :photo %>
<% form_for(:photo, :url => user_photo_path(@user, @photo), :html => {:method => :put}) do |f| %>
Description:
<%= f.text_area :description %>
<%= submit_tag 'Update Photo' %>
<% end %>

THE END!

That should be it. Please let me know if you come up with any errors, i have this working in a couple of demo apps that are on Rails 2.0.2, but may not have copied the code over perfectly.

http://therailscoder.blogspot.com