diff --git a/app/controllers/microposts_controller.rb b/app/controllers/microposts_controller.rb
index ff6b55e..be14e14 100644
--- a/app/controllers/microposts_controller.rb
+++ b/app/controllers/microposts_controller.rb
@@ -19,6 +19,12 @@ def create
@track.session_name = Track.get_session_name(content)
@track.name = Track.get_name(content, @track)
@track.save
+ elsif Picture.is_picture_upload_post? content
+ @picture = Picture.new(params[:micropost][:picture])
+ success_message = "Picture uploaded!"
+ @picture.session_name = Picture.get_session_name(content)
+ @picture.name = Picture.get_name(content, @picture)
+ @picture.save
end
params[:micropost][:content] = params[:micropost][:content][0..136] + '...'
diff --git a/app/controllers/pictures_controller.rb b/app/controllers/pictures_controller.rb
new file mode 100644
index 0000000..1da4b4d
--- /dev/null
+++ b/app/controllers/pictures_controller.rb
@@ -0,0 +1,9 @@
+class PicturesController < ApplicationController
+
+ def index
+ @pictures = Picture.all.shuffle
+
+ render :index, :layout => 'g_application'
+ end
+
+end
\ No newline at end of file
diff --git a/app/controllers/tracks_controller.rb b/app/controllers/tracks_controller.rb
index ed9c25b..e87524d 100644
--- a/app/controllers/tracks_controller.rb
+++ b/app/controllers/tracks_controller.rb
@@ -17,5 +17,17 @@ def frontpage
frontpage_tracks.first.toggle!(:frontpage) unless frontpage_tracks.count == 0
track.toggle!(:frontpage)
redirect_to :tracks
+ end
+
+ def makepublic
+ track = Track.find(params[:id])
+ track.toggle!(:public)
+ redirect_to :tracks
+ end
+
+ def makeprivate
+ track = Track.find(params[:id])
+ track.toggle!(:public)
+ redirect_to :tracks
end
end
diff --git a/app/helpers/tracks_helper.rb b/app/helpers/tracks_helper.rb
index 4769c0f..9a10de4 100644
--- a/app/helpers/tracks_helper.rb
+++ b/app/helpers/tracks_helper.rb
@@ -1,2 +1,13 @@
module TracksHelper
+
+ def get_track_status_action(track)
+ if not signed_in? then
+ return
+ end
+ if(track.public)
+ link_to "make private", tracks_private_path(track.id)
+ else
+ link_to "make public", tracks_public_path(track.id)
+ end
+ end
end
diff --git a/app/models/micropost.rb b/app/models/micropost.rb
index e45508a..8fc5a80 100644
--- a/app/models/micropost.rb
+++ b/app/models/micropost.rb
@@ -26,6 +26,10 @@ class Micropost < ActiveRecord::Base
def track
@track || (@track = Track.new)
end
+
+ def picture
+ @picture || (@picture = Picture.new)
+ end
private
diff --git a/app/models/picture.rb b/app/models/picture.rb
new file mode 100644
index 0000000..479a8c6
--- /dev/null
+++ b/app/models/picture.rb
@@ -0,0 +1,30 @@
+class Picture < ActiveRecord::Base
+ has_attached_file :image,
+ :storage => :s3,
+ :s3_credentials => "#{RAILS_ROOT}/config/s3.yml",
+ :path => 'images/:session_name/:basename.:extension',
+ :bucket => 'chriserin_paperclip_test'
+
+
+ class << self
+ def is_picture_upload_post?(post)
+ post =~ /^picture\supload/i
+ end
+
+ def get_name(post, track)
+ if(post =~/n=(\w.*)/i)
+ $1.split(" ")[0]
+ else
+ post.split(" ")[2].split('.')[0]
+ end
+ end
+
+ def get_session_name(post)
+ if(post =~/s=(\w.*)/i)
+ $1
+ else
+ Date.today.strftime('%d%b%y')
+ end
+ end
+ end
+end
diff --git a/app/views/layouts/g_application.html.erb b/app/views/layouts/g_application.html.erb
index 28c0aa7..268c1c4 100644
--- a/app/views/layouts/g_application.html.erb
+++ b/app/views/layouts/g_application.html.erb
@@ -5,7 +5,8 @@
<%= csrf_meta_tag %>
<%= render 'layouts/g_stylesheets' %>
<%= javascript_include_tag :defaults %>
- <%= javascript_include_tag 'jquery.jplayer.min' %>
+ <%= javascript_include_tag 'jquery.jplayer.min' %>
+ <%= javascript_include_tag 'jquery.masonry' %>
diff --git a/app/views/pictures/index.html.erb b/app/views/pictures/index.html.erb
new file mode 100644
index 0000000..01c43c3
--- /dev/null
+++ b/app/views/pictures/index.html.erb
@@ -0,0 +1,15 @@
+This is the pictures index.
+
+
+<% @pictures.each do |picture| %>
+ <%= image_tag picture.image.url %>
+<% end %>
+
+
+
\ No newline at end of file
diff --git a/app/views/shared/_micropost_form.html.erb b/app/views/shared/_micropost_form.html.erb
index 5fc1695..9d85852 100644
--- a/app/views/shared/_micropost_form.html.erb
+++ b/app/views/shared/_micropost_form.html.erb
@@ -10,5 +10,10 @@
<%= track_form.file_field :recording %>
+ <% end %>
+ <%= f.fields_for @micropost.picture do |picture_form| %>
+
+ <%= picture_form.file_field :image %>
+
<% end %>
<% end %>
\ No newline at end of file
diff --git a/app/views/tracks/_track.html.erb b/app/views/tracks/_track.html.erb
index 70dfd3c..ebe3cf5 100644
--- a/app/views/tracks/_track.html.erb
+++ b/app/views/tracks/_track.html.erb
@@ -1,5 +1,8 @@
+ <% if signed_in? or track.public? %>
<%= div_for track do %>
<%= link_to track.name, track.recording.url, :class => 'audio_link', :id => track.id %>
play
-
<%= link_to 'frontpage', tracks_frontpage_path(track.id) %>
- <% end %>
\ No newline at end of file
+
<%= link_to 'frontpage', tracks_frontpage_path(track.id) unless not signed_in? %>
+
<%= get_track_status_action(track) %>
+ <% end %>
+ <% end %>
\ No newline at end of file
diff --git a/config/routes.rb b/config/routes.rb
index db8f7eb..dbfb51f 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -12,13 +12,16 @@
resources :microposts, :only => [:create, :destroy]
resources :relationships, :only => [:create, :destroy]
resources :tracks, :only => [:index]
+ resources :pictures, :only => [:index]
root :to => "geronimo#index"
match "/myspace" => redirect("http://www.myspace.com/thegeronimoband")
match "/facebook" => redirect("http://www.facebook.com/thegeronimoband")
- match '/tracks/:id/frontpage', :to => 'tracks#frontpage', :as => 'tracks_frontpage'
+ match '/tracks/:id/frontpage', :to => 'tracks#frontpage', :as => 'tracks_frontpage'
+ match '/tracks/:id/makepublic', :to => 'tracks#makepublic', :as => 'tracks_public'
+ match '/tracks/:id/makeprivate', :to => 'tracks#makeprivate', :as => 'tracks_private'
match '/everything', :to => 'geronimo#everything'
match '/blogs', :to => 'geronimo#blogs'
match '/all_shows', :to => 'geronimo#shows'
@@ -29,61 +32,4 @@
match '/signin', :to => 'sessions#new'
match '/signout', :to => 'sessions#destroy'
match '/home', :to => 'pages#home'
-
- # The priority is based upon order of creation:
- # first created -> highest priority.
-
- # Sample of regular route:
- # match 'products/:id' => 'catalog#view'
- # Keep in mind you can assign values other than :controller and :action
-
- # Sample of named route:
- # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
- # This route can be invoked with purchase_url(:id => product.id)
-
- # Sample resource route (maps HTTP verbs to controller actions automatically):
- # resources :products
-
- # Sample resource route with options:
- # resources :products do
- # member do
- # get :short
- # post :toggle
- # end
- #
- # collection do
- # get :sold
- # end
- # end
-
- # Sample resource route with sub-resources:
- # resources :products do
- # resources :comments, :sales
- # resource :seller
- # end
-
- # Sample resource route with more complex sub-resources
- # resources :products do
- # resources :comments
- # resources :sales do
- # get :recent, :on => :collection
- # end
- # end
-
- # Sample resource route within a namespace:
- # namespace :admin do
- # # Directs /admin/products/* to Admin::ProductsController
- # # (app/controllers/admin/products_controller.rb)
- # resources :products
- # end
-
- # You can have the root of your site routed with "root"
- # just remember to delete public/index.html.
- # root :to => "welcome#index"
-
- # See how all your routes lay out with "rake routes"
-
- # This is a legacy wild controller route that's not recommended for RESTful applications.
- # Note: This route will make all actions in every controller accessible via GET requests.
- # match ':controller(/:action(/:id(.:format)))'
end
diff --git a/db/migrate/20110407224907_add_public_to_track.rb b/db/migrate/20110407224907_add_public_to_track.rb
new file mode 100644
index 0000000..8c1be76
--- /dev/null
+++ b/db/migrate/20110407224907_add_public_to_track.rb
@@ -0,0 +1,9 @@
+class AddPublicToTrack < ActiveRecord::Migration
+ def self.up
+ add_column :tracks, :public, :boolean
+ end
+
+ def self.down
+ remove_column :tracks, :public
+ end
+end
diff --git a/db/migrate/20110503191359_create_pictures.rb b/db/migrate/20110503191359_create_pictures.rb
new file mode 100644
index 0000000..0cd70b2
--- /dev/null
+++ b/db/migrate/20110503191359_create_pictures.rb
@@ -0,0 +1,17 @@
+class CreatePictures < ActiveRecord::Migration
+ def self.up
+ create_table :pictures do |t|
+ t.string :image_file_name
+ t.string :image_content_type
+ t.integer :image_file_size
+ t.datetime :image_updated_at
+ t.string :session_name
+ t.string :name
+ t.timestamps
+ end
+ end
+
+ def self.down
+ drop_table :pictures
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index fd96014..3cfbb24 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 20110224030948) do
+ActiveRecord::Schema.define(:version => 20110503191359) do
create_table "blogs", :force => true do |t|
t.integer "user_id"
@@ -31,6 +31,17 @@
add_index "microposts", ["user_id"], :name => "index_microposts_on_user_id"
+ create_table "pictures", :force => true do |t|
+ t.string "image_file_name"
+ t.string "image_content_type"
+ t.integer "image_file_size"
+ t.datetime "image_updated_at"
+ t.string "session_name"
+ t.string "name"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
create_table "relationships", :force => true do |t|
t.integer "follower_id"
t.integer "followed_id"
@@ -59,6 +70,7 @@
t.string "session_name"
t.string "name"
t.boolean "frontpage", :default => false
+ t.boolean "public"
end
create_table "users", :force => true do |t|
diff --git a/public/javascripts/application.js b/public/javascripts/application.js
index abca986..bd44229 100644
--- a/public/javascripts/application.js
+++ b/public/javascripts/application.js
@@ -5,20 +5,62 @@ $(function(){
if($("#micropost_content").val() == 'track upload')
{
document.getElementById("micropost_track_recording").click();
-
+ $("#track_chooser").css("z-index", 1);
+ }
+
+ if($("#micropost_content").val() == 'picture upload')
+ {
+ document.getElementById("micropost_picture_image").click();
+ $("#picture_chooser").css("z-index", 1);
}
});
$("#micropost_track_recording").bind('change', function(e)
{
- var filename = $("#micropost_track_recording").val().split(/\\/);
- $("#micropost_content").val($("#micropost_content").val() + filename[2]);
+ var filename = $("#micropost_track_recording").val()
+ if(filename.search(/\\/) > 0)
+ {
+ filename = filename.split(/\\/)[2];
+ }
+
+ $("#micropost_content").val($("#micropost_content").val() + filename);
+ $("#track_chooser").css("z-index", -1);
});
+
+ $("#micropost_picture_image").bind('change', function(e)
+ {
+ var filename = $("#micropost_picture_image").val();
+ if(filename.search(/\\/) > 0)
+ {
+ filename = filename.split(/\\/)[2];
+ }
+
+ $("#micropost_content").val($("#micropost_content").val() + filename);
+ $("#picture_chooser").css("z-index", -1);
+ });
$(".play_button").bind('click', function(e){
var filename = $(this).siblings('a').attr("href").split(/\?/)[0];
- alert(filename);
- $("#jquery_jplayer_1").jPlayer("setMedia", { mp3: filename });
+ var extension_array = filename.split(/\./);
+ var extension = extension_array[extension_array.length -1];
+
+
+ if(extension == 'mp3')
+ {
+ $("#jquery_jplayer_1").jPlayer("setMedia", { mp3: filename });
+ $("#jquery_jplayer_1").jPlayer("supplied", extension);
+ }
+ else if (extension == 'm4a')
+ {
+ $("#jquery_jplayer_1").jPlayer("setMedia", { m4a: filename });
+ $("#jquery_jplayer_1").jPlayer("supplied", extension);
+ }
+ else if (extension == 'ogg')
+ {
+ $("#jquery_jplayer_1").jPlayer("setMedia", { ogg: filename });
+ $("#jquery_jplayer_1").jPlayer("supplied", extension);
+ }
+
$("#jquery_jplayer_1").jPlayer("play");
$("#jp_playlist_1").html($(this).siblings('a').text());
});
diff --git a/public/javascripts/jquery.masonry.js b/public/javascripts/jquery.masonry.js
new file mode 100644
index 0000000..e127b3a
--- /dev/null
+++ b/public/javascripts/jquery.masonry.js
@@ -0,0 +1,298 @@
+/*************************************************
+** jQuery Masonry version 1.3.2
+** Copyright David DeSandro, licensed MIT
+** http://desandro.com/resources/jquery-masonry
+**************************************************/
+;(function($){
+
+ /*!
+ * smartresize: debounced resize event for jQuery
+ * http://github.com/lrbabe/jquery-smartresize
+ *
+ * Copyright (c) 2009 Louis-Remi Babe
+ * Licensed under the GPL license.
+ * http://docs.jquery.com/License
+ *
+ */
+ var event = $.event,
+ resizeTimeout;
+
+ event.special.smartresize = {
+ setup: function() {
+ $(this).bind( "resize", event.special.smartresize.handler );
+ },
+ teardown: function() {
+ $(this).unbind( "resize", event.special.smartresize.handler );
+ },
+ handler: function( event, execAsap ) {
+ // Save the context
+ var context = this,
+ args = arguments;
+
+ // set correct event type
+ event.type = "smartresize";
+
+ if (resizeTimeout) { clearTimeout(resizeTimeout); }
+ resizeTimeout = setTimeout(function() {
+ jQuery.event.handle.apply( context, args );
+ }, execAsap === "execAsap"? 0 : 100);
+ }
+ };
+
+ $.fn.smartresize = function( fn ) {
+ return fn ? this.bind( "smartresize", fn ) : this.trigger( "smartresize", ["execAsap"] );
+ };
+
+
+
+ // masonry code begin
+ $.fn.masonry = function(options, callback) {
+
+ // all my sweet methods
+ var msnry = {
+ getBricks : function($wall, props, opts) {
+ var hasItemSelector = (opts.itemSelector === undefined);
+ if ( opts.appendedContent === undefined ) {
+ // if not appendedContent
+ props.$bricks = hasItemSelector ?
+ $wall.children() :
+ $wall.find(opts.itemSelector);
+ } else {
+ // if appendedContent...
+ props.$bricks = hasItemSelector ?
+ opts.appendedContent :
+ opts.appendedContent.filter( opts.itemSelector );
+ }
+ },
+
+ placeBrick : function($brick, setCount, setY, props, opts) {
+ // get the minimum Y value from the columns...
+ var minimumY = Math.min.apply(Math, setY),
+ setHeight = minimumY + $brick.outerHeight(true),
+ i = setY.length,
+ shortCol = i,
+ setSpan = props.colCount + 1 - i;
+ // Which column has the minY value, closest to the left
+ while (i--) {
+ if ( setY[i] == minimumY ) {
+ shortCol = i;
+ }
+ }
+
+ var position = {
+ left: props.colW * shortCol + props.posLeft,
+ top: minimumY
+ };
+
+ // position the brick
+ $brick.applyStyle(position, $.extend(true,{},opts.animationOptions) );
+
+ // apply setHeight to necessary columns
+ for ( i=0; i < setSpan; i++ ) {
+ props.colY[ shortCol + i ] = setHeight;
+ }
+ },
+
+ setup : function($wall, opts, props) {
+ msnry.getBricks($wall, props, opts);
+
+ if ( props.masoned ) {
+ props.previousData = $wall.data('masonry');
+ }
+
+ if ( opts.columnWidth === undefined) {
+ props.colW = props.masoned ?
+ props.previousData.colW :
+ props.$bricks.outerWidth(true);
+ } else {
+ props.colW = opts.columnWidth;
+ }
+
+ props.colCount = Math.floor( $wall.width() / props.colW ) ;
+ props.colCount = Math.max( props.colCount, 1 );
+ },
+
+ arrange : function($wall, opts, props) {
+ var i;
+
+ if ( !props.masoned || opts.appendedContent !== undefined ) {
+ // just the new bricks
+ props.$bricks.css( 'position', 'absolute' );
+ }
+
+ // if masonry hasn't been called before
+ if ( !props.masoned ) {
+ $wall.css( 'position', 'relative' );
+
+ // get top left position of where the bricks should be
+ var $cursor = $( document.createElement('div') );
+ $wall.prepend( $cursor );
+ props.posTop = Math.round( $cursor.position().top );
+ props.posLeft = Math.round( $cursor.position().left );
+ $cursor.remove();
+ } else {
+ props.posTop = props.previousData.posTop;
+ props.posLeft = props.previousData.posLeft;
+ }
+
+ // set up column Y array
+ if ( props.masoned && opts.appendedContent !== undefined ) {
+ // if appendedContent is set, use colY from last call
+ props.colY = props.previousData.colY;
+
+ /*
+ * in the case that the wall is not resizeable,
+ * but the colCount has changed from the previous time
+ * masonry has been called
+ */
+ for ( i = props.previousData.colCount; i < props.colCount; i++) {
+ props.colY[i] = props.posTop;
+ }
+
+ } else {
+ // start new colY array, with starting values set to posTop
+ props.colY = [];
+ i = props.colCount;
+ while (i--) {
+ props.colY.push(props.posTop);
+ }
+ }
+
+ // are we animating the rearrangement?
+ // use plugin-ish syntax for css or animate
+ $.fn.applyStyle = ( props.masoned && opts.animate ) ? $.fn.animate : $.fn.css;
+
+
+ // layout logic
+ if ( opts.singleMode ) {
+ props.$bricks.each(function(){
+ var $brick = $(this);
+ msnry.placeBrick($brick, props.colCount, props.colY, props, opts);
+ });
+ } else {
+ props.$bricks.each(function() {
+ var $brick = $(this),
+ //how many columns does this brick span
+ colSpan = Math.ceil( $brick.outerWidth(true) / props.colW);
+ colSpan = Math.min( colSpan, props.colCount );
+
+ if ( colSpan === 1 ) {
+ // if brick spans only one column, just like singleMode
+ msnry.placeBrick($brick, props.colCount, props.colY, props, opts);
+ } else {
+ // brick spans more than one column
+
+ //how many different places could this brick fit horizontally
+ var groupCount = props.colCount + 1 - colSpan,
+ groupY = [];
+
+ // for each group potential horizontal position
+ for ( i=0; i < groupCount; i++ ) {
+ // make an array of colY values for that one group
+ var groupColY = props.colY.slice(i, i+colSpan);
+ // and get the max value of the array
+ groupY[i] = Math.max.apply(Math, groupColY);
+ }
+
+ msnry.placeBrick($brick, groupCount, groupY, props, opts);
+ }
+ }); // /props.bricks.each(function() {
+ } // /layout logic
+
+ // set the height of the wall to the tallest column
+ props.wallH = Math.max.apply(Math, props.colY);
+ var wallCSS = { height: props.wallH - props.posTop };
+ $wall.applyStyle( wallCSS, $.extend(true,[],opts.animationOptions) );
+
+ // add masoned class first time around
+ if ( !props.masoned ) {
+ // wait 1 millisec for quell transitions
+ setTimeout(function(){
+ $wall.addClass('masoned');
+ }, 1);
+ }
+
+ // provide props.bricks as context for the callback
+ callback.call( props.$bricks );
+
+ // set all data so we can retrieve it for appended appendedContent
+ // or anyone else's crazy jquery fun
+ $wall.data('masonry', props );
+
+ }, // /msnry.arrange
+
+ resize : function($wall, opts, props) {
+ props.masoned = !!$wall.data('masonry');
+ var prevColCount = $wall.data('masonry').colCount;
+ msnry.setup($wall, opts, props);
+ if ( props.colCount != prevColCount ) {
+ msnry.arrange($wall, opts, props);
+ }
+ }
+ };
+
+
+ /*
+ * let's begin
+ * IN A WORLD...
+ */
+ return this.each(function() {
+
+ var $wall = $(this),
+ props = {};
+
+ // checks if masonry has been called before on this object
+ props.masoned = !!$wall.data('masonry');
+
+ var previousOptions = props.masoned ? $wall.data('masonry').options : {},
+ opts = $.extend(
+ {},
+ $.fn.masonry.defaults,
+ previousOptions,
+ options
+ ),
+ resizeOn = previousOptions.resizeable;
+
+ // should we save these options for next time?
+ props.options = opts.saveOptions ? opts : previousOptions;
+
+ //picked up from Paul Irish
+ callback = callback || function(){};
+
+ msnry.getBricks($wall, props, opts);
+
+ // if brickParent is empty, do nothing, go back home and eat chips
+ if ( !props.$bricks.length ) {
+ return this;
+ }
+
+ // call masonry layout
+ msnry.setup($wall, opts, props);
+ msnry.arrange($wall, opts, props);
+
+ // binding window resizing
+ if ( !resizeOn && opts.resizeable ) {
+ $(window).bind('smartresize.masonry', function() { msnry.resize($wall, opts, props); } );
+ }
+ if ( resizeOn && !opts.resizeable ) {
+ $(window).unbind('smartresize.masonry');
+ }
+
+
+ }); // /return this.each(function()
+ }; // /$.fn.masonry = function(options)
+
+
+ // Default plugin options
+ $.fn.masonry.defaults = {
+ singleMode: false,
+ columnWidth: undefined,
+ itemSelector: undefined,
+ appendedContent: undefined,
+ saveOptions: true,
+ resizeable: true,
+ animate: false,
+ animationOptions: {}
+ };
+
+})(jQuery);
\ No newline at end of file
diff --git a/public/stylesheets/custom.css b/public/stylesheets/custom.css
index e53482a..f51ffd0 100644
--- a/public/stylesheets/custom.css
+++ b/public/stylesheets/custom.css
@@ -252,5 +252,16 @@ form.new_micropost textarea {
{
position: relative;
z-index: -1;
- margin-top: -40px;
-}
\ No newline at end of file
+ margin-top: -80px;
+ margin-bottom: 80px;
+}
+
+#picture_chooser
+{
+ position: relative;
+ z-index: -1;
+ margin-top: -100px;
+ margin-bottom: 100px;
+}
+
+
diff --git a/public/stylesheets/geronimo.css b/public/stylesheets/geronimo.css
index 1b9945d..2ecf5b5 100644
--- a/public/stylesheets/geronimo.css
+++ b/public/stylesheets/geronimo.css
@@ -297,4 +297,5 @@ nav ul li a:hover {
{
margin-top: 4px;
margin-bottom: 4px;
-}
\ No newline at end of file
+}
+
diff --git a/public/stylesheets/your_band.css b/public/stylesheets/your_band.css
index daffbf7..3b67217 100644
--- a/public/stylesheets/your_band.css
+++ b/public/stylesheets/your_band.css
@@ -8,4 +8,17 @@ audio
background-color: blue;
border-style: solid;
border-width: 5px;
+}
+
+img
+{
+ margin: 10px;
+ -moz-box-shadow: 0 0 20px 5px green;
+ -webkit-box-shadow: 0 0 20px 5px green;
+ box-shadow: 0 0 20px 5px green;
+}
+
+body
+{
+ background-color: red;
}
\ No newline at end of file
diff --git a/spec/models/picture_spec.rb b/spec/models/picture_spec.rb
new file mode 100644
index 0000000..5ef8eea
--- /dev/null
+++ b/spec/models/picture_spec.rb
@@ -0,0 +1,5 @@
+require 'spec_helper'
+
+describe Picture do
+ pending "add some examples to (or delete) #{__FILE__}"
+end