ruby script/generate scaffold album caption:string description:text user:references
class CreateAlbums < ActiveRecord::Migration
def self.up
create_table :albums do |t|
t.string :caption, :limit => 40, :null => false
t.text :description
t.references :user, :null => false
t.integer :pictures_count, :default => 0
t.timestamps
end
add_index :albums, [:user_id], :name => :albums_user_index
end
def self.down
remove_index :albums, :name => :albums_user_index
drop_table :albums
end
end
ruby script/generate scaffold picture caption:string description:text user:references album:references content_type:string width:integer height:integer
class CreatePictures < ActiveRecord::Migration
def self.up
create_table :pictures do |t|
t.string :caption, :limit => 40
t.text :description
t.references :user, :null => false
t.references :album, :null => false
t.string :content_type, :null => false
t.integer :width, :null => false
t.integer :height, :null => false
t.timestamps
end
add_index :pictures, [:user_id], :name => :pictures_user_index
add_index :pictures, [:album_id], :name => :pictures_album_index
end
def self.down
remove_index :pictures, :name => :pictures_album_index
remove_index :pictures, :name => :pictures_user_index
drop_table :pictures
end
end
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.string :name, :limit => 40, :null => false
t.string :motto, :limit => 80
t.string :salted_password, :limit => 40, :null => false
t.string :salt, :limit => 40, :null => false
t.integer :albums_count, :default => 0
t.integer :pictures_count, :default => 0
t.timestamps
end
add_index :users, [:name], :name => :users_name_index, :unique => true
end
def self.down
remove_index :users, :name => :users_name_index
drop_table :users
end
end
rake db:migrate VERSION=0 rake db:migrate
C:\Courses\LUGPC10\WebAlbum>rake db:migrate VERSION=0
(in C:/Courses/LUGPC10/WebAlbum)
== 1 CreateUsers: reverting ===================================================
-- remove_index(:users, {:name=>:users_name_index})
-> 0.0620s
-- drop_table(:users)
-> 0.0630s
== 1 CreateUsers: reverted (0.1250s) ==========================================
C:\Courses\LUGPC10\WebAlbum>rake db:migrate
(in C:/Courses/LUGPC10/WebAlbum)
== 1 CreateUsers: migrating ===================================================
-- create_table(:users)
-> 0.1570s
-- add_index(:users, [:name], {:name=>:users_name_index, :unique=>true})
-> 0.1250s
== 1 CreateUsers: migrated (0.2820s) ==========================================
== 2 CreateAlbums: migrating ==================================================
-- create_table(:albums)
-> 0.0940s
-- add_index(:albums, [:user_id], {:name=>:albums_user_index, :unique=>false})
-> 0.0780s
== 2 CreateAlbums: migrated (0.1720s) =========================================
== 3 CreatePictures: migrating ================================================
-- create_table(:pictures)
-> 0.0780s
-- add_index(:pictures, [:user_id], {:name=>:pictures_user_index, :unique=>false})
-> 0.0780s
-- add_index(:pictures, [:album_id], {:name=>:pictures_album_index, :unique=>false})
-> 0.0780s
== 3 CreatePictures: migrated (0.2340s) =======================================
...
def logout
session[:user_id] = nil
session[:album_id] = nil
redirect_to '/users'
end
...
helper_method :find_album
def find_album(id)
Album.find(:first, :conditions => [ "id = ?", id ])
end
helper_method :current_album
def current_album
@current_album ||= (session[:album_id] ? find_album(session[:album_id]) : nil)
end
helper_method :current_album=
def current_album=(id)
if current_user
session[:album_id] = id
else
session[:album_id] = nil
end
end
helper_method :all_albums
def all_albums
if current_user
return current_user.albums
else
return Album.find(:all, :order => "id DESC", :limit => 20 )
end
end
helper_method :all_pictures
def all_pictures
if current_user
return current_user.pictures
else
return Picture.find(:all, :order => "id DESC", :limit => 20 )
end
end
helper_method :user_albums
def user_albums
if current_user
return current_user.albums
else
return []
end
end
helper_method :current_user_owns?
def current_user_owns?(item)
logged_user = current_user
return true if logged_user && logged_user.id == item.user_id
false
end
end
<h1>New album</h1> <% if current_user %> <%= error_messages_for :album %> <% form_for(@album) do |f| %> <div> <%= f.label :caption, 'Caption:' %> <%= f.text_field :caption, :size => 40, :maxlength => 40 %> </div> <div> <%= f.label :description, 'Description:' %> <%= f.text_area :description, :rows => 4, :cols => 38 %> </div> <div> <%= f.hidden_field :user_id, :value => current_user.id %> <%= f.submit "Create", :class => 'button' %> </div> <% end %> <% else %> <p class='advise'> You must be logged in to create an album.<br /> Why not <%= link_to 'register', new_user_path %> now? </p> <% end %> <%= link_to 'Back', albums_path %>
...
class User < ActiveRecord::Base
has_many :albums, :order => "id DESC", :dependent => :destroy
has_many :pictures, :order => "id DESC", :dependent => :destroy
...
class Album < ActiveRecord::Base
belongs_to :user, :counter_cache => true
has_many :pictures, :order => "id DESC", :dependent => :destroy
validates_presence_of :user_id
validates_presence_of :caption
validates_length_of :caption, :within => 1..40
end


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<%= javascript_include_tag :defaults %>
<%= javascript_include_tag 'lightbox' %>
<% title = 'WebAlbum: ' +
controller.controller_name.capitalize + ': ' +
controller.action_name.capitalize %>
<title><%= title %></title>
<%= stylesheet_link_tag 'web_album' %>
<%= stylesheet_link_tag 'lightbox' %>
</head>
<body>
<%= render 'layouts/partials/header' %>
<div class='content'>
<div class='navigation'>
<%= link_to 'Users', users_path %> | 
<%= link_to 'Albums', albums_path %> | 
<%= link_to 'Pictures', pictures_path %>
</div>
<p style="color: green"><%= flash[:notice] %></p>
<%= yield %>
</div>
<%= render 'layouts/partials/footer' %>
</body>
</html>
ruby script/generate model image user:references picture:references size:integer data:binary content_type:string width:integer height:integer
class CreateImages < ActiveRecord::Migration
def self.up
create_table :images do |t|
t.references :user, :null => false
t.references :picture, :null => false
t.integer :size, :null => false
t.binary :data, :null => false
t.string :content_type, :null => false
t.integer :width, :null => false
t.integer :height, :null => false
t.timestamps
end
add_index :images, [:picture_id, :size], :name => :images_index
end
def self.down
remove_index :images, :name => :images_index
drop_table :images
end
end
rake db:migrate
class Image < ActiveRecord::Base belongs_to :user belongs_to :picture validates_presence_of :user_id validates_presence_of :picture_id validates_presence_of :size validates_presence_of :data validates_presence_of :content_type validates_presence_of :width validates_presence_of :height Original = 1 Large = 2 Medium = 3 Small = 4 Widths = [ 0, 0, 500, 250, 100 ] Heights = [ 0, 0, 500, 250, 100 ] Names = [ "", "Original", "Large", "Medium", "Small" ] def filename return Image.filename(picture_id, size) end def self.filename(id, size) if size == Original return "#{id}-#{Names[size]}.jpg" else return "#{id}-#{Names[size]}.gif" end end end
require 'RMagick'
class Picture < ActiveRecord::Base
belongs_to :user, :counter_cache => true
belongs_to :album, :counter_cache => true
has_many :images, :order => "size ASC", :dependent => :destroy
attr_accessor :operation
validates_presence_of :user_id
validates_presence_of :album_id
validates_length_of :caption, :within => 0..40
NoOp = 0
RotateClockWise90 = 1
RotateAntiClockWise90 = 2
Rotate180 = 3
Flip = 4
Flop = 5
def validate_on_create
errors.add_to_base(@picture_error) if @picture_error
end
def picture_file
@picture_filename
end
def picture_file=(field)
extract_picture field
end
def picture_image
@picture_image
end
private
def extract_picture(field)
@picture_error = @picture_image = nil
if field.class.method_defined? :original_filename
@picture_filename = field.original_filename
data = field.read
if data.length == 0
@picture_error = "Empty picture file: #{@picture_filename}"
else
begin
@picture_image = org = Magick::Image.from_blob(data).first
org.format = "JPG"
self.content_type = org.mime_type
self.width = org.columns
self.height = org.rows
rescue Magick::ImageMagickError
@picture_image = nil
@picture_error = "Unknown picture format: #{@picture_filename}"
end
end
else
@picture_error = "No picture filename specified"
end
end
end
...
# VIEW /image/:id/:size/:filename.:ext
def view
id = params[:id]
size = params[:size].to_i
case size
when Image::Original, Image::Large, Image::Medium, Image::Small
else
size = Image::Small
end
image = find_image id, size
if image
headers['Last-Modified'] = image.updated_at.httpdate
send_data(image.data, :filename => image.filename,
:type => image.content_type, :disposition => 'inline', :status => 200)
else
render :file => "./public/404.html", :type => 'text/html; charset=utf-8',
:status => 404
end
end
include RmagickHelper
end
require 'RMagick'
module RmagickHelper
private
def find_image(pic_id, size)
Image.find(:first, :conditions => [ "picture_id = ? AND size = ?", pic_id, size ])
end
def find_images(pic_id)
Image.find(:all, :order => "size ASC", :conditions => [ "picture_id = ?", pic_id ])
end
def save_all(picture)
begin
Picture.transaction do
picture.save!
org = picture.picture_image
images = create_all picture.id, picture.user_id
update_images images, org
images.each { |image| image.save! }
end
rescue
return false
end
true
end
def update_all(picture, params)
begin
Picture.transaction do
picture.update_attributes!(params)
operation = picture.operation
if operation && operation.to_i != Picture::NoOp
images = find_images picture.id
org = Magick::Image.from_blob(images[0].data).first
case operation.to_i
when Picture::RotateClockWise90 then changed = org.rotate(90)
when Picture::RotateAntiClockWise90 then changed = org.rotate(-90)
when Picture::Rotate180 then changed = org.rotate(180)
when Picture::Flip then changed = org.flip
when Picture::Flop then changed = org.flop
else return true
end
update_images images, changed
images.each { |image| image.save! }
picture.width = changed.columns
picture.height = changed.rows
picture.save!
end
end
rescue
return false
end
true
end
def dimensions(size)
[ Image::Widths[size], Image::Heights[size] ]
end
def create_all(pic_id, user_id)
[ Image.new(:user_id => user_id, :picture_id => pic_id, :size => Image::Original),
Image.new(:user_id => user_id, :picture_id => pic_id, :size => Image::Large),
Image.new(:user_id => user_id, :picture_id => pic_id, :size => Image::Medium),
Image.new(:user_id => user_id, :picture_id => pic_id, :size => Image::Small) ]
end
def update_images(images, original)
update_image(images[0], original)
large = resize_image(original, dimensions(Image::Large))
update_image(images[1], large)
update_image(images[2], resize_image(large, dimensions(Image::Medium), true))
update_image(images[3], resize_image(large, dimensions(Image::Small), true))
end
def update_image(image, data)
image.content_type = data.mime_type
image.width = data.columns
image.height = data.rows
image.data = data.to_blob
end
def resize_image(data, dims, reposition = false)
width = dims[0]
height = dims[1]
geometry = Magick::Geometry.new(width, height, nil, nil, Magick::GreaterGeometry)
data.change_geometry(geometry) do |cols, rows, img|
img = img.resize(cols, rows)
img.background_color = "transparent"
img.format = "GIF"
if reposition && (cols < width || rows < height)
img = img.extent(width, height, -((width - cols) / 2), -((height - rows) / 2))
end
img
end
end
end
<h1>New picture</h1> <% if current_user %> <% if @albums.length > 0 %> <%= error_messages_for :picture %> <% form_for(@picture, :html => { :enctype => "multipart/form-data", :onsubmit => "return Lightbox.block('Uploading picture, please wait...');" } ) do |f| %> <div> <%= f.label :caption, 'Caption:' %> <%= f.text_field :caption, :size => 40, :maxlength => 40 %> </div> <div> <%= f.label :description, 'Description:' %> <%= f.text_area :description, :rows => 4, :cols => 38 %> </div> <div> <%= f.hidden_field :user_id, :value => current_user.id %> <%= f.label :album_id, 'Album:' %> <% current_album_id = current_album ? current_album.id : @albums[0].id options = @albums.collect { |album| [album.caption, album.id] } %> <%= f.select :album_id, options, :selected => current_album_id %> </div> <div> <%= f.label :picture_file, 'Picture file:' %> <%= f.file_field :picture_file %> </div> <div> <%= f.submit "Create", :class = 'button' %> </div> <% end %> <% else %> <p class='advise'> You must have an album to create a picture.<br /> Why not <%= link_to 'create', new_album_path %> one now? </p> <% end %> <% else %> <p class='advise'> You must be logged in to create a picture.<br /> Why not <%= link_to 'register', new_user_path %> now? </p> <% end %> <%= link_to 'Back', pictures_path %>
<h1>Editing picture</h1> <% if current_user_owns? @picture %> <%= error_messages_for :picture %> <% form_for(@picture, :html => { :onsubmit => "return Lightbox.block('Modifying picture, please wait...');" } ) do |f| %> <div> <label>Image:</label> <span class='gallery'><%= picture_img @picture, Image::Medium %></span> </div> <div> <%= f.label :caption, 'Caption:' %> <%= f.text_field :caption, :size => 40, :maxlength => 40 %> </div> <div> <%= f.label :description, 'Description:' %> <%= f.text_area :description, :rows => 4, :cols => 38 %> </div> <div> <%= f.label :operation, 'Operation:' %> <% options = [ [ "None", Picture::NoOp ], [ "Rotate clockwise 90 degrees", Picture::RotateClockWise90 ], [ "Rotate anti-clockwise 90 degrees", Picture::RotateAntiClockWise90 ], [ "Rotate 180 degrees", Picture::Rotate180 ], [ "Vertical mirror image", Picture::Flip ], [ "Horizontal mirror image", Picture::Flop ] ] %> <%= f.select :operation, options, :selected => Picture::NoOp %> </div> <div> <%= f.hidden_field :user_id, :value => current_user.id %> <%= f.label :album_id, 'Album:' %> <% options = @albums.collect { |album| [album.caption, album.id] } %> <%= f.select :album_id, options, :selected => @picture.album_id %> </div> <div> <%= f.submit "Update", :class => 'button' %> </div> <% end %> <% else %> <p class='advise'>You must be logged in as the owner to edit this picture.</p> <% end %> <%= link_to 'Show', @picture %> | <%= link_to 'Back', pictures_path %>
ActionController::Routing::Routes.draw do |map|
map.root :controller => 'users', :action => 'index'
map.connect 'image/:id/:size/:filename.:ext', :controller => 'pictures', :action => 'view'
...
...
def picture_lightbox(picture, size, lightbox_size)
caption = picture.caption
caption = '...' if caption.nil? || caption.blank?
link = h("<a href=\"#{picture_url(picture.id, Image::Original)}\" title=\"View Original\" target=\"_blank\">#{caption.gsub(/'/, ''')}</a>")
"<a href='#{picture_url(picture.id, lightbox_size)}' rel='lightbox[list]' title=\"#{link}\">#{picture_img(picture, size)}</a>"
end
def picture_a(picture, size, html_tag)
html_tag = '...' if html_tag.nil? || html_tag.blank?
"<a href='#{picture_url(picture.id, size)}' target='_blank'>#{html_tag}</a>"
end
def picture_img(picture, size)
width = 0
height = 0
case size
when Image::Original
width = picture.width
height = picture.height
else
width = Image::Widths[size]
height = Image::Widths[size]
end
"<img src='#{picture_url(picture.id, size)}' alt=\"#{h picture.caption}\" title=\"#{h picture.caption}\" width='#{width}' height='#{height}' />"
end
private
def picture_url(id, size)
"/image/#{id}/#{size}/#{Image.filename(id, size)}"
end
end
<%= javascript_tag "document.observe('dom:loaded', Lightbox.onload);" %>




Courses:
Tutorials:
Tag cloud: