From 5ae5e0f9594b7938a546bceac59f30069131b2a4 Mon Sep 17 00:00:00 2001 From: Skud Date: Wed, 8 May 2013 20:52:35 +1000 Subject: [PATCH 01/27] rails g scaffold Photo... --- app/assets/javascripts/photos.js.coffee | 3 + app/controllers/photos_controller.rb | 83 ++++++++++++ app/helpers/photos_helper.rb | 2 + app/models/member.rb | 1 + app/models/photo.rb | 4 + app/views/photos/_form.html.haml | 22 ++++ app/views/photos/edit.html.haml | 7 + app/views/photos/index.html.haml | 25 ++++ app/views/photos/new.html.haml | 5 + app/views/photos/show.html.haml | 18 +++ config/routes.rb | 3 + db/migrate/20130508104506_create_photos.rb | 12 ++ db/schema.rb | 11 +- spec/controllers/photos_controller_spec.rb | 146 +++++++++++++++++++++ spec/factories/photos.rb | 10 ++ spec/helpers/photos_helper_spec.rb | 15 +++ spec/models/photo_spec.rb | 5 + spec/requests/photos_spec.rb | 11 ++ spec/routing/photos_routing_spec.rb | 35 +++++ spec/views/photos/edit.html.haml_spec.rb | 24 ++++ spec/views/photos/index.html.haml_spec.rb | 29 ++++ spec/views/photos/new.html.haml_spec.rb | 24 ++++ spec/views/photos/show.html.haml_spec.rb | 21 +++ 23 files changed, 515 insertions(+), 1 deletion(-) create mode 100644 app/assets/javascripts/photos.js.coffee create mode 100644 app/controllers/photos_controller.rb create mode 100644 app/helpers/photos_helper.rb create mode 100644 app/models/photo.rb create mode 100644 app/views/photos/_form.html.haml create mode 100644 app/views/photos/edit.html.haml create mode 100644 app/views/photos/index.html.haml create mode 100644 app/views/photos/new.html.haml create mode 100644 app/views/photos/show.html.haml create mode 100644 db/migrate/20130508104506_create_photos.rb create mode 100644 spec/controllers/photos_controller_spec.rb create mode 100644 spec/factories/photos.rb create mode 100644 spec/helpers/photos_helper_spec.rb create mode 100644 spec/models/photo_spec.rb create mode 100644 spec/requests/photos_spec.rb create mode 100644 spec/routing/photos_routing_spec.rb create mode 100644 spec/views/photos/edit.html.haml_spec.rb create mode 100644 spec/views/photos/index.html.haml_spec.rb create mode 100644 spec/views/photos/new.html.haml_spec.rb create mode 100644 spec/views/photos/show.html.haml_spec.rb diff --git a/app/assets/javascripts/photos.js.coffee b/app/assets/javascripts/photos.js.coffee new file mode 100644 index 000000000..761567942 --- /dev/null +++ b/app/assets/javascripts/photos.js.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/app/controllers/photos_controller.rb b/app/controllers/photos_controller.rb new file mode 100644 index 000000000..b5ac8c9f7 --- /dev/null +++ b/app/controllers/photos_controller.rb @@ -0,0 +1,83 @@ +class PhotosController < ApplicationController + # GET /photos + # GET /photos.json + def index + @photos = Photo.all + + respond_to do |format| + format.html # index.html.erb + format.json { render json: @photos } + end + end + + # GET /photos/1 + # GET /photos/1.json + def show + @photo = Photo.find(params[:id]) + + respond_to do |format| + format.html # show.html.erb + format.json { render json: @photo } + end + end + + # GET /photos/new + # GET /photos/new.json + def new + @photo = Photo.new + + respond_to do |format| + format.html # new.html.erb + format.json { render json: @photo } + end + end + + # GET /photos/1/edit + def edit + @photo = Photo.find(params[:id]) + end + + # POST /photos + # POST /photos.json + def create + @photo = Photo.new(params[:photo]) + + respond_to do |format| + if @photo.save + format.html { redirect_to @photo, notice: 'Photo was successfully created.' } + format.json { render json: @photo, status: :created, location: @photo } + else + format.html { render action: "new" } + format.json { render json: @photo.errors, status: :unprocessable_entity } + end + end + end + + # PUT /photos/1 + # PUT /photos/1.json + def update + @photo = Photo.find(params[:id]) + + respond_to do |format| + if @photo.update_attributes(params[:photo]) + format.html { redirect_to @photo, notice: 'Photo was successfully updated.' } + format.json { head :no_content } + else + format.html { render action: "edit" } + format.json { render json: @photo.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /photos/1 + # DELETE /photos/1.json + def destroy + @photo = Photo.find(params[:id]) + @photo.destroy + + respond_to do |format| + format.html { redirect_to photos_url } + format.json { head :no_content } + end + end +end diff --git a/app/helpers/photos_helper.rb b/app/helpers/photos_helper.rb new file mode 100644 index 000000000..0a10d472b --- /dev/null +++ b/app/helpers/photos_helper.rb @@ -0,0 +1,2 @@ +module PhotosHelper +end diff --git a/app/models/member.rb b/app/models/member.rb index 3e3790a46..95863bb73 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -11,6 +11,7 @@ class Member < ActiveRecord::Base has_many :notifications, :foreign_key => 'recipient_id' has_many :sent_notifications, :foreign_key => 'sender_id' has_many :authentications + has_many :photos default_scope order("lower(login_name) asc") scope :confirmed, where('confirmed_at IS NOT NULL') diff --git a/app/models/photo.rb b/app/models/photo.rb new file mode 100644 index 000000000..24e3cc581 --- /dev/null +++ b/app/models/photo.rb @@ -0,0 +1,4 @@ +class Photo < ActiveRecord::Base + attr_accessible :flickr_photo_id, :fullsize_url, :owner_id, :thumbnail_url + belongs_to :owner, :class_name => 'Member' +end diff --git a/app/views/photos/_form.html.haml b/app/views/photos/_form.html.haml new file mode 100644 index 000000000..8745c195b --- /dev/null +++ b/app/views/photos/_form.html.haml @@ -0,0 +1,22 @@ += form_for @photo do |f| + - if @photo.errors.any? + #error_explanation + %h2= "#{pluralize(@photo.errors.count, "error")} prohibited this photo from being saved:" + %ul + - @photo.errors.full_messages.each do |msg| + %li= msg + + .field + = f.label :owner_id + = f.number_field :owner_id + .field + = f.label :flickr_photo_id + = f.number_field :flickr_photo_id + .field + = f.label :thumbnail_url + = f.text_field :thumbnail_url + .field + = f.label :fullsize_url + = f.text_field :fullsize_url + .actions + = f.submit 'Save' diff --git a/app/views/photos/edit.html.haml b/app/views/photos/edit.html.haml new file mode 100644 index 000000000..73440055c --- /dev/null +++ b/app/views/photos/edit.html.haml @@ -0,0 +1,7 @@ +%h1 Editing photo + += render 'form' + += link_to 'Show', @photo +\| += link_to 'Back', photos_path diff --git a/app/views/photos/index.html.haml b/app/views/photos/index.html.haml new file mode 100644 index 000000000..3f16c5677 --- /dev/null +++ b/app/views/photos/index.html.haml @@ -0,0 +1,25 @@ +%h1 Listing photos + +%table + %tr + %th Owner + %th Flickr photo + %th Thumbnail url + %th Fullsize url + %th + %th + %th + + - @photos.each do |photo| + %tr + %td= photo.owner_id + %td= photo.flickr_photo_id + %td= photo.thumbnail_url + %td= photo.fullsize_url + %td= link_to 'Show', photo + %td= link_to 'Edit', edit_photo_path(photo) + %td= link_to 'Destroy', photo, :method => :delete, :data => { :confirm => 'Are you sure?' } + +%br + += link_to 'New Photo', new_photo_path diff --git a/app/views/photos/new.html.haml b/app/views/photos/new.html.haml new file mode 100644 index 000000000..9506ac3ce --- /dev/null +++ b/app/views/photos/new.html.haml @@ -0,0 +1,5 @@ +%h1 New photo + += render 'form' + += link_to 'Back', photos_path diff --git a/app/views/photos/show.html.haml b/app/views/photos/show.html.haml new file mode 100644 index 000000000..093aaedec --- /dev/null +++ b/app/views/photos/show.html.haml @@ -0,0 +1,18 @@ +%p#notice= notice + +%p + %b Owner: + = @photo.owner_id +%p + %b Flickr photo: + = @photo.flickr_photo_id +%p + %b Thumbnail url: + = @photo.thumbnail_url +%p + %b Fullsize url: + = @photo.fullsize_url + += link_to 'Edit', edit_photo_path(@photo) +\| += link_to 'Back', photos_path diff --git a/config/routes.rb b/config/routes.rb index cf757e9af..2398cc988 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,8 @@ Growstuff::Application.routes.draw do + resources :photos + + devise_for :members, :controllers => { :registrations => "registrations" } resources :authentications diff --git a/db/migrate/20130508104506_create_photos.rb b/db/migrate/20130508104506_create_photos.rb new file mode 100644 index 000000000..f7c56188d --- /dev/null +++ b/db/migrate/20130508104506_create_photos.rb @@ -0,0 +1,12 @@ +class CreatePhotos < ActiveRecord::Migration + def change + create_table :photos do |t| + t.integer :owner_id, :null => false + t.integer :flickr_photo_id, :null => false + t.string :thumbnail_url, :null => false + t.string :fullsize_url, :null => false + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 090be1b27..e6810afb1 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20130508050711) do +ActiveRecord::Schema.define(:version => 20130508104506) do create_table "authentications", :force => true do |t| t.integer "member_id", :null => false @@ -140,6 +140,15 @@ ActiveRecord::Schema.define(:version => 20130508050711) do t.datetime "updated_at", :null => false end + create_table "photos", :force => true do |t| + t.integer "owner_id", :null => false + t.integer "flickr_photo_id", :null => false + t.string "thumbnail_url", :null => false + t.string "fullsize_url", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + create_table "plantings", :force => true do |t| t.integer "garden_id", :null => false t.integer "crop_id", :null => false diff --git a/spec/controllers/photos_controller_spec.rb b/spec/controllers/photos_controller_spec.rb new file mode 100644 index 000000000..b1c74fb75 --- /dev/null +++ b/spec/controllers/photos_controller_spec.rb @@ -0,0 +1,146 @@ +require 'spec_helper' + + +describe PhotosController do + + def valid_attributes + { + "owner_id" => "1", + "flickr_photo_id" => 1, + "thumbnail_url" => 'http://example.com', + "fullsize_url" => 'http://example.com' + } + end + + def valid_session + {} + end + + describe "GET index" do + it "assigns all photos as @photos" do + photo = Photo.create! valid_attributes + get :index, {}, valid_session + assigns(:photos).should eq([photo]) + end + end + + describe "GET show" do + it "assigns the requested photo as @photo" do + photo = Photo.create! valid_attributes + get :show, {:id => photo.to_param}, valid_session + assigns(:photo).should eq(photo) + end + end + + describe "GET new" do + it "assigns a new photo as @photo" do + get :new, {}, valid_session + assigns(:photo).should be_a_new(Photo) + end + end + + describe "GET edit" do + it "assigns the requested photo as @photo" do + photo = Photo.create! valid_attributes + get :edit, {:id => photo.to_param}, valid_session + assigns(:photo).should eq(photo) + end + end + + describe "POST create" do + describe "with valid params" do + it "creates a new Photo" do + expect { + post :create, {:photo => valid_attributes}, valid_session + }.to change(Photo, :count).by(1) + end + + it "assigns a newly created photo as @photo" do + post :create, {:photo => valid_attributes}, valid_session + assigns(:photo).should be_a(Photo) + assigns(:photo).should be_persisted + end + + it "redirects to the created photo" do + post :create, {:photo => valid_attributes}, valid_session + response.should redirect_to(Photo.last) + end + end + + describe "with invalid params" do + it "assigns a newly created but unsaved photo as @photo" do + # Trigger the behavior that occurs when invalid params are submitted + Photo.any_instance.stub(:save).and_return(false) + post :create, {:photo => { "owner_id" => "invalid value" }}, valid_session + assigns(:photo).should be_a_new(Photo) + end + + it "re-renders the 'new' template" do + # Trigger the behavior that occurs when invalid params are submitted + Photo.any_instance.stub(:save).and_return(false) + post :create, {:photo => { "owner_id" => "invalid value" }}, valid_session + response.should render_template("new") + end + end + end + + describe "PUT update" do + describe "with valid params" do + it "updates the requested photo" do + photo = Photo.create! valid_attributes + # Assuming there are no other photos in the database, this + # specifies that the Photo created on the previous line + # receives the :update_attributes message with whatever params are + # submitted in the request. + Photo.any_instance.should_receive(:update_attributes).with({ "owner_id" => "1" }) + put :update, {:id => photo.to_param, :photo => { "owner_id" => "1" }}, valid_session + end + + it "assigns the requested photo as @photo" do + photo = Photo.create! valid_attributes + put :update, {:id => photo.to_param, :photo => valid_attributes}, valid_session + assigns(:photo).should eq(photo) + end + + it "redirects to the photo" do + photo = Photo.create! valid_attributes + put :update, {:id => photo.to_param, :photo => valid_attributes}, valid_session + response.should redirect_to(photo) + end + end + + describe "with invalid params" do + it "assigns the photo as @photo" do + photo = Photo.create! valid_attributes + # Trigger the behavior that occurs when invalid params are submitted + Photo.any_instance.stub(:save).and_return(false) + put :update, {:id => photo.to_param, :photo => { "owner_id" => "invalid value" }}, valid_session + assigns(:photo).should eq(photo) + end + + it "re-renders the 'edit' template" do + photo = Photo.create! valid_attributes + # Trigger the behavior that occurs when invalid params are submitted + Photo.any_instance.stub(:save).and_return(false) + put :update, {:id => photo.to_param, :photo => { "owner_id" => "invalid value" }}, valid_session + response.should render_template("edit") + end + end + end + + describe "DELETE destroy" do + it "destroys the requested photo" do + photo = Photo.create! valid_attributes + expect { + delete :destroy, {:id => photo.to_param}, valid_session + }.to change(Photo, :count).by(-1) + end + + it "redirects to the photos list" do + photo = Photo.create! valid_attributes + delete :destroy, {:id => photo.to_param}, valid_session + response.should redirect_to(photos_url) + end + end + +end diff --git a/spec/factories/photos.rb b/spec/factories/photos.rb new file mode 100644 index 000000000..409d2bdf0 --- /dev/null +++ b/spec/factories/photos.rb @@ -0,0 +1,10 @@ +# Read about factories at https://github.com/thoughtbot/factory_girl + +FactoryGirl.define do + factory :photo do + owner_id 1 + flickr_photo_id 1 + thumbnail_url "MyString" + fullsize_url "MyString" + end +end diff --git a/spec/helpers/photos_helper_spec.rb b/spec/helpers/photos_helper_spec.rb new file mode 100644 index 000000000..c4b452740 --- /dev/null +++ b/spec/helpers/photos_helper_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +# Specs in this file have access to a helper object that includes +# the PhotosHelper. For example: +# +# describe PhotosHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# helper.concat_strings("this","that").should == "this that" +# end +# end +# end +describe PhotosHelper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/photo_spec.rb b/spec/models/photo_spec.rb new file mode 100644 index 000000000..0cfe452fe --- /dev/null +++ b/spec/models/photo_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe Photo do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/requests/photos_spec.rb b/spec/requests/photos_spec.rb new file mode 100644 index 000000000..bfb595245 --- /dev/null +++ b/spec/requests/photos_spec.rb @@ -0,0 +1,11 @@ +require 'spec_helper' + +describe "Photos" do + describe "GET /photos" do + it "works! (now write some real specs)" do + # Run the generator again with the --webrat flag if you want to use webrat methods/matchers + get photos_path + response.status.should be(200) + end + end +end diff --git a/spec/routing/photos_routing_spec.rb b/spec/routing/photos_routing_spec.rb new file mode 100644 index 000000000..d7dc394ed --- /dev/null +++ b/spec/routing/photos_routing_spec.rb @@ -0,0 +1,35 @@ +require "spec_helper" + +describe PhotosController do + describe "routing" do + + it "routes to #index" do + get("/photos").should route_to("photos#index") + end + + it "routes to #new" do + get("/photos/new").should route_to("photos#new") + end + + it "routes to #show" do + get("/photos/1").should route_to("photos#show", :id => "1") + end + + it "routes to #edit" do + get("/photos/1/edit").should route_to("photos#edit", :id => "1") + end + + it "routes to #create" do + post("/photos").should route_to("photos#create") + end + + it "routes to #update" do + put("/photos/1").should route_to("photos#update", :id => "1") + end + + it "routes to #destroy" do + delete("/photos/1").should route_to("photos#destroy", :id => "1") + end + + end +end diff --git a/spec/views/photos/edit.html.haml_spec.rb b/spec/views/photos/edit.html.haml_spec.rb new file mode 100644 index 000000000..fa4c72673 --- /dev/null +++ b/spec/views/photos/edit.html.haml_spec.rb @@ -0,0 +1,24 @@ +require 'spec_helper' + +describe "photos/edit" do + before(:each) do + @photo = assign(:photo, stub_model(Photo, + :owner_id => 1, + :flickr_photo_id => 1, + :thumbnail_url => "MyString", + :fullsize_url => "MyString" + )) + end + + it "renders the edit photo form" do + render + + # Run the generator again with the --webrat flag if you want to use webrat matchers + assert_select "form", :action => photos_path(@photo), :method => "post" do + assert_select "input#photo_owner_id", :name => "photo[owner_id]" + assert_select "input#photo_flickr_photo_id", :name => "photo[flickr_photo_id]" + assert_select "input#photo_thumbnail_url", :name => "photo[thumbnail_url]" + assert_select "input#photo_fullsize_url", :name => "photo[fullsize_url]" + end + end +end diff --git a/spec/views/photos/index.html.haml_spec.rb b/spec/views/photos/index.html.haml_spec.rb new file mode 100644 index 000000000..8dc87e540 --- /dev/null +++ b/spec/views/photos/index.html.haml_spec.rb @@ -0,0 +1,29 @@ +require 'spec_helper' + +describe "photos/index" do + before(:each) do + assign(:photos, [ + stub_model(Photo, + :owner_id => 1, + :flickr_photo_id => 2, + :thumbnail_url => "Thumbnail Url", + :fullsize_url => "Fullsize Url" + ), + stub_model(Photo, + :owner_id => 1, + :flickr_photo_id => 2, + :thumbnail_url => "Thumbnail Url", + :fullsize_url => "Fullsize Url" + ) + ]) + end + + it "renders a list of photos" do + render + # Run the generator again with the --webrat flag if you want to use webrat matchers + assert_select "tr>td", :text => 1.to_s, :count => 2 + assert_select "tr>td", :text => 2.to_s, :count => 2 + assert_select "tr>td", :text => "Thumbnail Url".to_s, :count => 2 + assert_select "tr>td", :text => "Fullsize Url".to_s, :count => 2 + end +end diff --git a/spec/views/photos/new.html.haml_spec.rb b/spec/views/photos/new.html.haml_spec.rb new file mode 100644 index 000000000..fdf65d126 --- /dev/null +++ b/spec/views/photos/new.html.haml_spec.rb @@ -0,0 +1,24 @@ +require 'spec_helper' + +describe "photos/new" do + before(:each) do + assign(:photo, stub_model(Photo, + :owner_id => 1, + :flickr_photo_id => 1, + :thumbnail_url => "MyString", + :fullsize_url => "MyString" + ).as_new_record) + end + + it "renders new photo form" do + render + + # Run the generator again with the --webrat flag if you want to use webrat matchers + assert_select "form", :action => photos_path, :method => "post" do + assert_select "input#photo_owner_id", :name => "photo[owner_id]" + assert_select "input#photo_flickr_photo_id", :name => "photo[flickr_photo_id]" + assert_select "input#photo_thumbnail_url", :name => "photo[thumbnail_url]" + assert_select "input#photo_fullsize_url", :name => "photo[fullsize_url]" + end + end +end diff --git a/spec/views/photos/show.html.haml_spec.rb b/spec/views/photos/show.html.haml_spec.rb new file mode 100644 index 000000000..0eb478998 --- /dev/null +++ b/spec/views/photos/show.html.haml_spec.rb @@ -0,0 +1,21 @@ +require 'spec_helper' + +describe "photos/show" do + before(:each) do + @photo = assign(:photo, stub_model(Photo, + :owner_id => 1, + :flickr_photo_id => 2, + :thumbnail_url => "Thumbnail Url", + :fullsize_url => "Fullsize Url" + )) + end + + it "renders attributes in

" do + render + # Run the generator again with the --webrat flag if you want to use webrat matchers + rendered.should match(/1/) + rendered.should match(/2/) + rendered.should match(/Thumbnail Url/) + rendered.should match(/Fullsize Url/) + end +end From ffb5d6e7f81d5ebb9392125532d4364d55d11352 Mon Sep 17 00:00:00 2001 From: Skud Date: Wed, 8 May 2013 20:54:48 +1000 Subject: [PATCH 02/27] only members can manage photos --- app/controllers/photos_controller.rb | 1 + app/models/ability.rb | 4 +++ spec/controllers/photos_controller_spec.rb | 35 +++++++++++----------- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/app/controllers/photos_controller.rb b/app/controllers/photos_controller.rb index b5ac8c9f7..8a1df7ed0 100644 --- a/app/controllers/photos_controller.rb +++ b/app/controllers/photos_controller.rb @@ -1,4 +1,5 @@ class PhotosController < ApplicationController + load_and_authorize_resource # GET /photos # GET /photos.json def index diff --git a/app/models/ability.rb b/app/models/ability.rb index e8ffaf75c..d128c4717 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -65,6 +65,10 @@ class Ability can :create, Planting can :update, Planting, :garden => { :owner_id => member.id } can :destroy, Planting, :garden => { :owner_id => member.id } + + can :create, Photo + can :update, Photo, :owner_id => member.id + can :destroy, Photo, :owner_id => member.id end end end diff --git a/spec/controllers/photos_controller_spec.rb b/spec/controllers/photos_controller_spec.rb index b1c74fb75..7f0c3bbfc 100644 --- a/spec/controllers/photos_controller_spec.rb +++ b/spec/controllers/photos_controller_spec.rb @@ -1,8 +1,9 @@ require 'spec_helper' - describe PhotosController do + login_member + def valid_attributes { "owner_id" => "1", @@ -19,7 +20,7 @@ describe PhotosController do describe "GET index" do it "assigns all photos as @photos" do photo = Photo.create! valid_attributes - get :index, {}, valid_session + get :index, {} assigns(:photos).should eq([photo]) end end @@ -27,14 +28,14 @@ describe PhotosController do describe "GET show" do it "assigns the requested photo as @photo" do photo = Photo.create! valid_attributes - get :show, {:id => photo.to_param}, valid_session + get :show, {:id => photo.to_param} assigns(:photo).should eq(photo) end end describe "GET new" do it "assigns a new photo as @photo" do - get :new, {}, valid_session + get :new, {} assigns(:photo).should be_a_new(Photo) end end @@ -42,7 +43,7 @@ describe PhotosController do describe "GET edit" do it "assigns the requested photo as @photo" do photo = Photo.create! valid_attributes - get :edit, {:id => photo.to_param}, valid_session + get :edit, {:id => photo.to_param} assigns(:photo).should eq(photo) end end @@ -51,18 +52,18 @@ describe PhotosController do describe "with valid params" do it "creates a new Photo" do expect { - post :create, {:photo => valid_attributes}, valid_session + post :create, {:photo => valid_attributes} }.to change(Photo, :count).by(1) end it "assigns a newly created photo as @photo" do - post :create, {:photo => valid_attributes}, valid_session + post :create, {:photo => valid_attributes} assigns(:photo).should be_a(Photo) assigns(:photo).should be_persisted end it "redirects to the created photo" do - post :create, {:photo => valid_attributes}, valid_session + post :create, {:photo => valid_attributes} response.should redirect_to(Photo.last) end end @@ -71,14 +72,14 @@ describe PhotosController do it "assigns a newly created but unsaved photo as @photo" do # Trigger the behavior that occurs when invalid params are submitted Photo.any_instance.stub(:save).and_return(false) - post :create, {:photo => { "owner_id" => "invalid value" }}, valid_session + post :create, {:photo => { "owner_id" => "invalid value" }} assigns(:photo).should be_a_new(Photo) end it "re-renders the 'new' template" do # Trigger the behavior that occurs when invalid params are submitted Photo.any_instance.stub(:save).and_return(false) - post :create, {:photo => { "owner_id" => "invalid value" }}, valid_session + post :create, {:photo => { "owner_id" => "invalid value" }} response.should render_template("new") end end @@ -93,18 +94,18 @@ describe PhotosController do # receives the :update_attributes message with whatever params are # submitted in the request. Photo.any_instance.should_receive(:update_attributes).with({ "owner_id" => "1" }) - put :update, {:id => photo.to_param, :photo => { "owner_id" => "1" }}, valid_session + put :update, {:id => photo.to_param, :photo => { "owner_id" => "1" }} end it "assigns the requested photo as @photo" do photo = Photo.create! valid_attributes - put :update, {:id => photo.to_param, :photo => valid_attributes}, valid_session + put :update, {:id => photo.to_param, :photo => valid_attributes} assigns(:photo).should eq(photo) end it "redirects to the photo" do photo = Photo.create! valid_attributes - put :update, {:id => photo.to_param, :photo => valid_attributes}, valid_session + put :update, {:id => photo.to_param, :photo => valid_attributes} response.should redirect_to(photo) end end @@ -114,7 +115,7 @@ describe PhotosController do photo = Photo.create! valid_attributes # Trigger the behavior that occurs when invalid params are submitted Photo.any_instance.stub(:save).and_return(false) - put :update, {:id => photo.to_param, :photo => { "owner_id" => "invalid value" }}, valid_session + put :update, {:id => photo.to_param, :photo => { "owner_id" => "invalid value" }} assigns(:photo).should eq(photo) end @@ -122,7 +123,7 @@ describe PhotosController do photo = Photo.create! valid_attributes # Trigger the behavior that occurs when invalid params are submitted Photo.any_instance.stub(:save).and_return(false) - put :update, {:id => photo.to_param, :photo => { "owner_id" => "invalid value" }}, valid_session + put :update, {:id => photo.to_param, :photo => { "owner_id" => "invalid value" }} response.should render_template("edit") end end @@ -132,13 +133,13 @@ describe PhotosController do it "destroys the requested photo" do photo = Photo.create! valid_attributes expect { - delete :destroy, {:id => photo.to_param}, valid_session + delete :destroy, {:id => photo.to_param} }.to change(Photo, :count).by(-1) end it "redirects to the photos list" do photo = Photo.create! valid_attributes - delete :destroy, {:id => photo.to_param}, valid_session + delete :destroy, {:id => photo.to_param} response.should redirect_to(photos_url) end end From acf164990d15dcaa26c4a620d68276a9bec220a1 Mon Sep 17 00:00:00 2001 From: Skud Date: Wed, 8 May 2013 21:17:03 +1000 Subject: [PATCH 03/27] tell user to connect to flickr --- app/controllers/authentications_controller.rb | 2 +- app/controllers/photos_controller.rb | 1 + app/views/photos/new.html.haml | 11 ++++++++--- spec/controllers/photos_controller_spec.rb | 8 ++++++++ spec/views/photos/new.html.haml_spec.rb | 10 ++++------ 5 files changed, 22 insertions(+), 10 deletions(-) diff --git a/app/controllers/authentications_controller.rb b/app/controllers/authentications_controller.rb index 96456d996..b4e376dca 100644 --- a/app/controllers/authentications_controller.rb +++ b/app/controllers/authentications_controller.rb @@ -37,7 +37,7 @@ class AuthenticationsController < ApplicationController else flash[:notice] = "Authentication failed." end - redirect_to edit_member_registration_path + redirect_to request.env['omniauth.origin'] || edit_member_registration_path end # DELETE /authentications/1 diff --git a/app/controllers/photos_controller.rb b/app/controllers/photos_controller.rb index 8a1df7ed0..d4fc62f5e 100644 --- a/app/controllers/photos_controller.rb +++ b/app/controllers/photos_controller.rb @@ -26,6 +26,7 @@ class PhotosController < ApplicationController # GET /photos/new.json def new @photo = Photo.new + @flickr_auth = current_member.authentications.find_by_provider('flickr') respond_to do |format| format.html # new.html.erb diff --git a/app/views/photos/new.html.haml b/app/views/photos/new.html.haml index 9506ac3ce..c4de9cd39 100644 --- a/app/views/photos/new.html.haml +++ b/app/views/photos/new.html.haml @@ -1,5 +1,10 @@ -%h1 New photo +- content_for :title, "New Photo" -= render 'form' +- if @flickr_auth + = render 'form' +- else + .alert + You must + =link_to "connect your account to Flickr", '/auth/flickr' + to add photos. -= link_to 'Back', photos_path diff --git a/spec/controllers/photos_controller_spec.rb b/spec/controllers/photos_controller_spec.rb index 7f0c3bbfc..f3432148e 100644 --- a/spec/controllers/photos_controller_spec.rb +++ b/spec/controllers/photos_controller_spec.rb @@ -34,6 +34,14 @@ describe PhotosController do end describe "GET new" do + it "assigns the flickr auth as @flickr_auth" do + @member = FactoryGirl.create(:member) + sign_in @member + @auth = FactoryGirl.create(:flickr_authentication, :member => @member) + get :new, {} + assigns(:flickr_auth).should be_an_instance_of(Authentication) + end + it "assigns a new photo as @photo" do get :new, {} assigns(:photo).should be_a_new(Photo) diff --git a/spec/views/photos/new.html.haml_spec.rb b/spec/views/photos/new.html.haml_spec.rb index fdf65d126..042a5dbcf 100644 --- a/spec/views/photos/new.html.haml_spec.rb +++ b/spec/views/photos/new.html.haml_spec.rb @@ -2,12 +2,10 @@ require 'spec_helper' describe "photos/new" do before(:each) do - assign(:photo, stub_model(Photo, - :owner_id => 1, - :flickr_photo_id => 1, - :thumbnail_url => "MyString", - :fullsize_url => "MyString" - ).as_new_record) + @member = FactoryGirl.create(:member) + controller.stub(:current_user) { @member } + assign(:photo, FactoryGirl.create(:photo)) + assign(:flickr_auth, FactoryGirl.create(:flickr_authentication, :member => @member)) end it "renders new photo form" do From cc6d6633cc8a5af901f119797bc21086bdbcab97 Mon Sep 17 00:00:00 2001 From: Skud Date: Wed, 8 May 2013 22:01:09 +1000 Subject: [PATCH 04/27] Rough attempt at showing photos from flickr. You can see a list of your recently uploaded Flickr photos at /photos/new, which is nice! However the tests are broken and there's a lot of mess that should be in the model instead of the controller. Committing as-is because I'm tired. --- Gemfile | 1 + Gemfile.lock | 2 ++ app/controllers/photos_controller.rb | 14 ++++++++++++++ app/views/photos/_form.html.haml | 22 ---------------------- app/views/photos/edit.html.haml | 7 +------ app/views/photos/new.html.haml | 22 +++++++++++++++++++++- 6 files changed, 39 insertions(+), 29 deletions(-) delete mode 100644 app/views/photos/_form.html.haml diff --git a/Gemfile b/Gemfile index 3f4318236..6eb4bbca7 100644 --- a/Gemfile +++ b/Gemfile @@ -36,6 +36,7 @@ group :assets do end gem 'jquery-rails' +gem 'flickraw' # To use ActiveModel has_secure_password # gem 'bcrypt-ruby', '~> 3.0.0' diff --git a/Gemfile.lock b/Gemfile.lock index 35ab7f28b..6c7782522 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -85,6 +85,7 @@ GEM factory_girl (~> 4.2.0) railties (>= 3.0.0) fastthread (1.0.7) + flickraw (0.9.6) friendly_id (4.0.9) fssm (0.2.10) geocoder (1.1.6) @@ -247,6 +248,7 @@ DEPENDENCIES devise diff-lcs factory_girl_rails (~> 4.0) + flickraw friendly_id geocoder gravatar-ultimate diff --git a/app/controllers/photos_controller.rb b/app/controllers/photos_controller.rb index d4fc62f5e..2454ab668 100644 --- a/app/controllers/photos_controller.rb +++ b/app/controllers/photos_controller.rb @@ -26,8 +26,22 @@ class PhotosController < ApplicationController # GET /photos/new.json def new @photo = Photo.new + + # NOTE: we should move a bunch of this into the Member model + @flickr_login = nil @flickr_auth = current_member.authentications.find_by_provider('flickr') + if @flickr_auth + FlickRaw.api_key = ENV['FLICKR_KEY'] + FlickRaw.shared_secret = ENV['FLICKR_SECRET'] + flickr = FlickRaw::Flickr.new + flickr.access_token = @flickr_auth.token + flickr.access_secret = @flickr_auth.secret + @flickr_login = flickr.test.login + + @photos = flickr.people.getPhotos(:user_id => 'me', :per_page => 30) + end + respond_to do |format| format.html # new.html.erb format.json { render json: @photo } diff --git a/app/views/photos/_form.html.haml b/app/views/photos/_form.html.haml deleted file mode 100644 index 8745c195b..000000000 --- a/app/views/photos/_form.html.haml +++ /dev/null @@ -1,22 +0,0 @@ -= form_for @photo do |f| - - if @photo.errors.any? - #error_explanation - %h2= "#{pluralize(@photo.errors.count, "error")} prohibited this photo from being saved:" - %ul - - @photo.errors.full_messages.each do |msg| - %li= msg - - .field - = f.label :owner_id - = f.number_field :owner_id - .field - = f.label :flickr_photo_id - = f.number_field :flickr_photo_id - .field - = f.label :thumbnail_url - = f.text_field :thumbnail_url - .field - = f.label :fullsize_url - = f.text_field :fullsize_url - .actions - = f.submit 'Save' diff --git a/app/views/photos/edit.html.haml b/app/views/photos/edit.html.haml index 73440055c..5a43dd437 100644 --- a/app/views/photos/edit.html.haml +++ b/app/views/photos/edit.html.haml @@ -1,7 +1,2 @@ -%h1 Editing photo +- content_for :title, "Edit Photo" -= render 'form' - -= link_to 'Show', @photo -\| -= link_to 'Back', photos_path diff --git a/app/views/photos/new.html.haml b/app/views/photos/new.html.haml index c4de9cd39..f23caecdb 100644 --- a/app/views/photos/new.html.haml +++ b/app/views/photos/new.html.haml @@ -1,7 +1,27 @@ - content_for :title, "New Photo" - if @flickr_auth - = render 'form' + %p + Connected to Flickr as + = succeed "." do + = link_to @flickr_login.username, "http://flickr.com/photos/#{@flickr_login.id}" + + %p Select a photo from your recent uploads: + + - c = 0 + %ul.thumbnails + .row + - @photos.each do |p| + - c += 1 + %li.span2 + .thumbnail(style='height: 220px') + = image_tag(FlickRaw.url_q(p), :alt => '', :class => 'img-rounded') + %p + =p.title + - if (c % 6) == 0 + .row + + - else .alert You must From ce3de63a46a72e8dedd4ad756e91c4bda9c71ad1 Mon Sep 17 00:00:00 2001 From: Miles Gould Date: Wed, 8 May 2013 14:59:08 +0100 Subject: [PATCH 05/27] Factor out flickr controller code, for easier stubbing. --- app/controllers/photos_controller.rb | 26 +++++++++++++++------- spec/controllers/photos_controller_spec.rb | 2 ++ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/app/controllers/photos_controller.rb b/app/controllers/photos_controller.rb index 2454ab668..460f8f60c 100644 --- a/app/controllers/photos_controller.rb +++ b/app/controllers/photos_controller.rb @@ -22,6 +22,22 @@ class PhotosController < ApplicationController end end + # I really hate the mixture of side-effects and return values here. + # It's done like this for easier mocking. Hopefully it'll soon be deleted! + def login_to_flickr() + FlickRaw.api_key = ENV['FLICKR_KEY'] + FlickRaw.shared_secret = ENV['FLICKR_SECRET'] + flickr = FlickRaw::Flickr.new + flickr.access_token = @flickr_auth.token + flickr.access_secret = @flickr_auth.secret + @flickr_login = flickr.test.login + return flickr + end + + def get_photos(flickr) + @photos = flickr.people.getPhotos(:user_id => 'me', :per_page => 30) + end + # GET /photos/new # GET /photos/new.json def new @@ -32,14 +48,8 @@ class PhotosController < ApplicationController @flickr_auth = current_member.authentications.find_by_provider('flickr') if @flickr_auth - FlickRaw.api_key = ENV['FLICKR_KEY'] - FlickRaw.shared_secret = ENV['FLICKR_SECRET'] - flickr = FlickRaw::Flickr.new - flickr.access_token = @flickr_auth.token - flickr.access_secret = @flickr_auth.secret - @flickr_login = flickr.test.login - - @photos = flickr.people.getPhotos(:user_id => 'me', :per_page => 30) + flickr = login_to_flickr() + get_photos(flickr) end respond_to do |format| diff --git a/spec/controllers/photos_controller_spec.rb b/spec/controllers/photos_controller_spec.rb index f3432148e..306d758e9 100644 --- a/spec/controllers/photos_controller_spec.rb +++ b/spec/controllers/photos_controller_spec.rb @@ -38,6 +38,8 @@ describe PhotosController do @member = FactoryGirl.create(:member) sign_in @member @auth = FactoryGirl.create(:flickr_authentication, :member => @member) + subject.stub(:login_to_flickr) + subject.stub(:get_photos) { [FactoryGirl.create(:photo)] } get :new, {} assigns(:flickr_auth).should be_an_instance_of(Authentication) end From 8af105fad73f3774129d38a48b43e144e62cddd5 Mon Sep 17 00:00:00 2001 From: Miles Gould Date: Wed, 8 May 2013 15:27:10 +0100 Subject: [PATCH 06/27] Test for photo thumbnails; stub Flickr username/id. --- spec/views/photos/new.html.haml_spec.rb | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/spec/views/photos/new.html.haml_spec.rb b/spec/views/photos/new.html.haml_spec.rb index 042a5dbcf..1657f59cf 100644 --- a/spec/views/photos/new.html.haml_spec.rb +++ b/spec/views/photos/new.html.haml_spec.rb @@ -4,19 +4,16 @@ describe "photos/new" do before(:each) do @member = FactoryGirl.create(:member) controller.stub(:current_user) { @member } - assign(:photo, FactoryGirl.create(:photo)) + flickr_login = double("flickr_login") + flickr_login.stub(:username) { @member.login_name } + flickr_login.stub(:id) { 1337 } + assign(:flickr_login, flickr_login) + assign(:photos, []) assign(:flickr_auth, FactoryGirl.create(:flickr_authentication, :member => @member)) end - it "renders new photo form" do + it "shows a list of photos" do render - - # Run the generator again with the --webrat flag if you want to use webrat matchers - assert_select "form", :action => photos_path, :method => "post" do - assert_select "input#photo_owner_id", :name => "photo[owner_id]" - assert_select "input#photo_flickr_photo_id", :name => "photo[flickr_photo_id]" - assert_select "input#photo_thumbnail_url", :name => "photo[thumbnail_url]" - assert_select "input#photo_fullsize_url", :name => "photo[fullsize_url]" - end + assert_select "ul.thumbnails" end end From 2fb8c380199f76b65af756255e5d0a114b0e7a9a Mon Sep 17 00:00:00 2001 From: Miles Gould Date: Wed, 8 May 2013 15:39:17 +0100 Subject: [PATCH 07/27] Removed obsolete test from views/photos/edit We should consider just deleting this action entirely. --- spec/views/photos/edit.html.haml_spec.rb | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/spec/views/photos/edit.html.haml_spec.rb b/spec/views/photos/edit.html.haml_spec.rb index fa4c72673..3b8cde557 100644 --- a/spec/views/photos/edit.html.haml_spec.rb +++ b/spec/views/photos/edit.html.haml_spec.rb @@ -10,15 +10,4 @@ describe "photos/edit" do )) end - it "renders the edit photo form" do - render - - # Run the generator again with the --webrat flag if you want to use webrat matchers - assert_select "form", :action => photos_path(@photo), :method => "post" do - assert_select "input#photo_owner_id", :name => "photo[owner_id]" - assert_select "input#photo_flickr_photo_id", :name => "photo[flickr_photo_id]" - assert_select "input#photo_thumbnail_url", :name => "photo[thumbnail_url]" - assert_select "input#photo_fullsize_url", :name => "photo[fullsize_url]" - end - end end From 035946edcd24d8977a790a40fe3616075082afc8 Mon Sep 17 00:00:00 2001 From: Miles Gould Date: Wed, 8 May 2013 15:55:32 +0100 Subject: [PATCH 08/27] "auth" helper method in Member --- app/controllers/members_controller.rb | 4 ++-- app/controllers/photos_controller.rb | 2 +- app/controllers/registrations_controller.rb | 4 ++-- app/models/member.rb | 4 ++++ 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/controllers/members_controller.rb b/app/controllers/members_controller.rb index d05c85f01..846d28f0a 100644 --- a/app/controllers/members_controller.rb +++ b/app/controllers/members_controller.rb @@ -12,8 +12,8 @@ class MembersController < ApplicationController def show @member = Member.confirmed.find(params[:id]) - @twitter_auth = @member.authentications.find_by_provider('twitter') - @flickr_auth = @member.authentications.find_by_provider('flickr') + @twitter_auth = @member.auth('twitter') + @flickr_auth = @member.auth('flickr') @posts = @member.posts # The garden form partial is called from the "New Garden" tab; # it requires a garden to be passed in @garden. diff --git a/app/controllers/photos_controller.rb b/app/controllers/photos_controller.rb index 460f8f60c..1ff5ec057 100644 --- a/app/controllers/photos_controller.rb +++ b/app/controllers/photos_controller.rb @@ -45,7 +45,7 @@ class PhotosController < ApplicationController # NOTE: we should move a bunch of this into the Member model @flickr_login = nil - @flickr_auth = current_member.authentications.find_by_provider('flickr') + @flickr_auth = current_member.auth('flickr') if @flickr_auth flickr = login_to_flickr() diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb index e23bebf0c..2be1c9c33 100644 --- a/app/controllers/registrations_controller.rb +++ b/app/controllers/registrations_controller.rb @@ -2,8 +2,8 @@ class RegistrationsController < Devise::RegistrationsController def edit - @twitter_auth = current_member.authentications.find_by_provider('twitter') - @flickr_auth = current_member.authentications.find_by_provider('flickr') + @twitter_auth = current_member.auth('twitter') + @flickr_auth = current_member.auth('flickr') render "edit" end diff --git a/app/models/member.rb b/app/models/member.rb index 95863bb73..8e6f2b5d3 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -86,6 +86,10 @@ class Member < ActiveRecord::Base roles.any? { |r| r.name.gsub(/\s+/, "_").underscore.to_sym == role_sym } end + def auth(provider) + return authentications.find_by_provider(provider) + end + protected def empty_unwanted_geocodes if self.location.to_s == '' From 016172f0e134d206e252d56581bb8bb4ad8cedb7 Mon Sep 17 00:00:00 2001 From: Miles Gould Date: Wed, 8 May 2013 16:23:54 +0100 Subject: [PATCH 09/27] Delete @flickr_login var in photos controller. We didn't need any data from it that couldn't be got from @flickr_auth, and eliminating it makes login_to_flickr less side-effecting and easier to move around. --- app/controllers/photos_controller.rb | 2 -- app/views/photos/new.html.haml | 2 +- spec/views/photos/new.html.haml_spec.rb | 4 ---- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/app/controllers/photos_controller.rb b/app/controllers/photos_controller.rb index 1ff5ec057..f48d659e2 100644 --- a/app/controllers/photos_controller.rb +++ b/app/controllers/photos_controller.rb @@ -30,7 +30,6 @@ class PhotosController < ApplicationController flickr = FlickRaw::Flickr.new flickr.access_token = @flickr_auth.token flickr.access_secret = @flickr_auth.secret - @flickr_login = flickr.test.login return flickr end @@ -44,7 +43,6 @@ class PhotosController < ApplicationController @photo = Photo.new # NOTE: we should move a bunch of this into the Member model - @flickr_login = nil @flickr_auth = current_member.auth('flickr') if @flickr_auth diff --git a/app/views/photos/new.html.haml b/app/views/photos/new.html.haml index f23caecdb..e93f99920 100644 --- a/app/views/photos/new.html.haml +++ b/app/views/photos/new.html.haml @@ -4,7 +4,7 @@ %p Connected to Flickr as = succeed "." do - = link_to @flickr_login.username, "http://flickr.com/photos/#{@flickr_login.id}" + = link_to @flickr_auth.name, "http://flickr.com/photos/#{@flickr_auth.uid}" %p Select a photo from your recent uploads: diff --git a/spec/views/photos/new.html.haml_spec.rb b/spec/views/photos/new.html.haml_spec.rb index 1657f59cf..1ea5a34d9 100644 --- a/spec/views/photos/new.html.haml_spec.rb +++ b/spec/views/photos/new.html.haml_spec.rb @@ -4,10 +4,6 @@ describe "photos/new" do before(:each) do @member = FactoryGirl.create(:member) controller.stub(:current_user) { @member } - flickr_login = double("flickr_login") - flickr_login.stub(:username) { @member.login_name } - flickr_login.stub(:id) { 1337 } - assign(:flickr_login, flickr_login) assign(:photos, []) assign(:flickr_auth, FactoryGirl.create(:flickr_authentication, :member => @member)) end From ae785c6f4b2255eb40a6987161969051a73453af Mon Sep 17 00:00:00 2001 From: Miles Gould Date: Wed, 8 May 2013 16:43:30 +0100 Subject: [PATCH 10/27] Move flickr code into Member model. --- app/controllers/photos_controller.rb | 20 +------------------- app/models/member.rb | 18 ++++++++++++++++++ spec/controllers/photos_controller_spec.rb | 4 ++-- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/app/controllers/photos_controller.rb b/app/controllers/photos_controller.rb index f48d659e2..a99724427 100644 --- a/app/controllers/photos_controller.rb +++ b/app/controllers/photos_controller.rb @@ -22,32 +22,14 @@ class PhotosController < ApplicationController end end - # I really hate the mixture of side-effects and return values here. - # It's done like this for easier mocking. Hopefully it'll soon be deleted! - def login_to_flickr() - FlickRaw.api_key = ENV['FLICKR_KEY'] - FlickRaw.shared_secret = ENV['FLICKR_SECRET'] - flickr = FlickRaw::Flickr.new - flickr.access_token = @flickr_auth.token - flickr.access_secret = @flickr_auth.secret - return flickr - end - - def get_photos(flickr) - @photos = flickr.people.getPhotos(:user_id => 'me', :per_page => 30) - end - # GET /photos/new # GET /photos/new.json def new @photo = Photo.new - # NOTE: we should move a bunch of this into the Member model @flickr_auth = current_member.auth('flickr') - if @flickr_auth - flickr = login_to_flickr() - get_photos(flickr) + @photos = current_member.flickr_photos end respond_to do |format| diff --git a/app/models/member.rb b/app/models/member.rb index 8e6f2b5d3..53f8c0a73 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -90,6 +90,24 @@ class Member < ActiveRecord::Base return authentications.find_by_provider(provider) end + def flickr + if @flickr.nil? + flickr_auth = auth('flickr') + if flickr_auth + FlickRaw.api_key = ENV['FLICKR_KEY'] + FlickRaw.shared_secret = ENV['FLICKR_SECRET'] + @flickr = FlickRaw::Flickr.new + @flickr.access_token = flickr_auth.token + @flickr.access_secret = flickr_auth.secret + end + end + return @flickr + end + + def flickr_photos + return flickr.people.getPhotos(:user_id => 'me', :per_page => 30) + end + protected def empty_unwanted_geocodes if self.location.to_s == '' diff --git a/spec/controllers/photos_controller_spec.rb b/spec/controllers/photos_controller_spec.rb index 306d758e9..1d0e8f740 100644 --- a/spec/controllers/photos_controller_spec.rb +++ b/spec/controllers/photos_controller_spec.rb @@ -37,9 +37,9 @@ describe PhotosController do it "assigns the flickr auth as @flickr_auth" do @member = FactoryGirl.create(:member) sign_in @member + @member.stub(:flickr_photos) { [] } + controller.stub(:current_member) { @member } @auth = FactoryGirl.create(:flickr_authentication, :member => @member) - subject.stub(:login_to_flickr) - subject.stub(:get_photos) { [FactoryGirl.create(:photo)] } get :new, {} assigns(:flickr_auth).should be_an_instance_of(Authentication) end From 6fa94e321a3fa71566cb45db523d21b3baf64926 Mon Sep 17 00:00:00 2001 From: Miles Gould Date: Thu, 9 May 2013 13:12:54 +0100 Subject: [PATCH 11/27] Save photos. --- app/controllers/photos_controller.rb | 2 ++ app/models/photo.rb | 17 +++++++++++++++++ app/views/photos/new.html.haml | 2 +- spec/controllers/photos_controller_spec.rb | 11 ++++++++--- spec/models/photo_spec.rb | 11 ++++++++++- 5 files changed, 38 insertions(+), 5 deletions(-) diff --git a/app/controllers/photos_controller.rb b/app/controllers/photos_controller.rb index a99724427..7434c17ae 100644 --- a/app/controllers/photos_controller.rb +++ b/app/controllers/photos_controller.rb @@ -47,6 +47,8 @@ class PhotosController < ApplicationController # POST /photos.json def create @photo = Photo.new(params[:photo]) + @photo.owner_id = current_member.id + @photo.set_flickr_urls respond_to do |format| if @photo.save diff --git a/app/models/photo.rb b/app/models/photo.rb index 24e3cc581..7c80ef53c 100644 --- a/app/models/photo.rb +++ b/app/models/photo.rb @@ -1,4 +1,21 @@ class Photo < ActiveRecord::Base attr_accessible :flickr_photo_id, :fullsize_url, :owner_id, :thumbnail_url belongs_to :owner, :class_name => 'Member' + + # This is split into a side-effect free method and a side-effecting method + # for easier stubbing and testing. + def flickr_urls + flickr = owner.flickr + info = flickr.photos.getInfo(:photo_id => flickr_photo_id) + thumb = FlickRaw.url_q(info) + full = FlickRaw.url_z(info) + return [thumb, full] + end + + def set_flickr_urls + urls = flickr_urls + self.thumbnail_url = urls[0] + self.fullsize_url = urls[1] + end + end diff --git a/app/views/photos/new.html.haml b/app/views/photos/new.html.haml index e93f99920..8bfdc7ab9 100644 --- a/app/views/photos/new.html.haml +++ b/app/views/photos/new.html.haml @@ -15,7 +15,7 @@ - c += 1 %li.span2 .thumbnail(style='height: 220px') - = image_tag(FlickRaw.url_q(p), :alt => '', :class => 'img-rounded') + = link_to image_tag(FlickRaw.url_q(p), :alt => '', :class => 'img-rounded'), photos_path(:photo => { :flickr_photo_id => p.id }), :method => :post %p =p.title - if (c % 6) == 0 diff --git a/spec/controllers/photos_controller_spec.rb b/spec/controllers/photos_controller_spec.rb index 1d0e8f740..63a638b1c 100644 --- a/spec/controllers/photos_controller_spec.rb +++ b/spec/controllers/photos_controller_spec.rb @@ -59,21 +59,26 @@ describe PhotosController do end describe "POST create" do + before(:each) do + Photo.any_instance.stub(:flickr_urls).and_return( + ["http://example.com", "http://example.com" ] + ) + end describe "with valid params" do it "creates a new Photo" do expect { - post :create, {:photo => valid_attributes} + post :create, {:photo => { :flickr_photo_id => 1 } } }.to change(Photo, :count).by(1) end it "assigns a newly created photo as @photo" do - post :create, {:photo => valid_attributes} + post :create, {:photo => { :flickr_photo_id => 1 } } assigns(:photo).should be_a(Photo) assigns(:photo).should be_persisted end it "redirects to the created photo" do - post :create, {:photo => valid_attributes} + post :create, {:photo => { :flickr_photo_id => 1 } } response.should redirect_to(Photo.last) end end diff --git a/spec/models/photo_spec.rb b/spec/models/photo_spec.rb index 0cfe452fe..1b8bbfbf8 100644 --- a/spec/models/photo_spec.rb +++ b/spec/models/photo_spec.rb @@ -1,5 +1,14 @@ require 'spec_helper' describe Photo do - pending "add some examples to (or delete) #{__FILE__}" + + describe 'generate_flickr_urls' do + # Any further tests led to us MOCKING ALL THE THINGS + # which was epistemologically unsatisfactory. + # So we're just going to test that the method exists. + it 'exists' do + photo = Photo.new(:owner_id => 1) + photo.should.respond_to? :generate_flickr_urls + end + end end From 536760ccae3ccc31f124d328d9af236b9c38ba18 Mon Sep 17 00:00:00 2001 From: Miles Gould Date: Thu, 9 May 2013 13:24:23 +0100 Subject: [PATCH 12/27] Show image on photos/show. Placeholder text for metadata. --- app/views/photos/show.html.haml | 27 +++++++++++------------- spec/factories/photos.rb | 4 ++-- spec/views/photos/show.html.haml_spec.rb | 15 +++---------- 3 files changed, 17 insertions(+), 29 deletions(-) diff --git a/app/views/photos/show.html.haml b/app/views/photos/show.html.haml index 093aaedec..c27d217f7 100644 --- a/app/views/photos/show.html.haml +++ b/app/views/photos/show.html.haml @@ -1,18 +1,15 @@ %p#notice= notice -%p - %b Owner: - = @photo.owner_id -%p - %b Flickr photo: - = @photo.flickr_photo_id -%p - %b Thumbnail url: - = @photo.thumbnail_url -%p - %b Fullsize url: - = @photo.fullsize_url += image_tag(@photo.fullsize_url, :alt => 'A plant', :class => 'img-rounded') + +%p + [Photo title goes here] + by + [Flickr username goes here] + on Flickr. + [if licence] + Licensed under [Licence goes here]. + [else] + [Copyright, all rights reserved] + [endif] -= link_to 'Edit', edit_photo_path(@photo) -\| -= link_to 'Back', photos_path diff --git a/spec/factories/photos.rb b/spec/factories/photos.rb index 409d2bdf0..40f7824b2 100644 --- a/spec/factories/photos.rb +++ b/spec/factories/photos.rb @@ -4,7 +4,7 @@ FactoryGirl.define do factory :photo do owner_id 1 flickr_photo_id 1 - thumbnail_url "MyString" - fullsize_url "MyString" + thumbnail_url "http://example.com/thumb.jpg" + fullsize_url "http://example.com/full.jpg" end end diff --git a/spec/views/photos/show.html.haml_spec.rb b/spec/views/photos/show.html.haml_spec.rb index 0eb478998..a7298fe7c 100644 --- a/spec/views/photos/show.html.haml_spec.rb +++ b/spec/views/photos/show.html.haml_spec.rb @@ -2,20 +2,11 @@ require 'spec_helper' describe "photos/show" do before(:each) do - @photo = assign(:photo, stub_model(Photo, - :owner_id => 1, - :flickr_photo_id => 2, - :thumbnail_url => "Thumbnail Url", - :fullsize_url => "Fullsize Url" - )) + @photo = assign(:photo, FactoryGirl.create(:photo)) end - it "renders attributes in

" do + it "shows the image" do render - # Run the generator again with the --webrat flag if you want to use webrat matchers - rendered.should match(/1/) - rendered.should match(/2/) - rendered.should match(/Thumbnail Url/) - rendered.should match(/Fullsize Url/) + assert_select "img[src=#{@photo.fullsize_url}]" end end From 746386731a813c431c23800c4556d8111bb3c903 Mon Sep 17 00:00:00 2001 From: Miles Gould Date: Thu, 9 May 2013 14:51:38 +0100 Subject: [PATCH 13/27] Add metadata to photos and display it on photos/show. --- app/controllers/photos_controller.rb | 2 +- app/models/photo.rb | 25 +++++++----- app/views/photos/show.html.haml | 18 +++++---- .../20130509123711_add_metadata_to_photos.rb | 22 +++++++++++ db/schema.rb | 6 ++- spec/controllers/photos_controller_spec.rb | 18 ++++++--- spec/factories/photos.rb | 11 +++++- spec/models/photo_spec.rb | 4 +- spec/views/photos/show.html.haml_spec.rb | 39 ++++++++++++++++--- 9 files changed, 112 insertions(+), 33 deletions(-) create mode 100644 db/migrate/20130509123711_add_metadata_to_photos.rb diff --git a/app/controllers/photos_controller.rb b/app/controllers/photos_controller.rb index 7434c17ae..960fd36bc 100644 --- a/app/controllers/photos_controller.rb +++ b/app/controllers/photos_controller.rb @@ -48,7 +48,7 @@ class PhotosController < ApplicationController def create @photo = Photo.new(params[:photo]) @photo.owner_id = current_member.id - @photo.set_flickr_urls + @photo.set_flickr_metadata respond_to do |format| if @photo.save diff --git a/app/models/photo.rb b/app/models/photo.rb index 7c80ef53c..84b22bcdd 100644 --- a/app/models/photo.rb +++ b/app/models/photo.rb @@ -1,21 +1,28 @@ class Photo < ActiveRecord::Base - attr_accessible :flickr_photo_id, :fullsize_url, :owner_id, :thumbnail_url + attr_accessible :flickr_photo_id, :owner_id, :title, :license_name, + :license_url, :thumbnail_url, :fullsize_url, :link_url belongs_to :owner, :class_name => 'Member' # This is split into a side-effect free method and a side-effecting method # for easier stubbing and testing. - def flickr_urls + def flickr_metadata flickr = owner.flickr info = flickr.photos.getInfo(:photo_id => flickr_photo_id) - thumb = FlickRaw.url_q(info) - full = FlickRaw.url_z(info) - return [thumb, full] + licenses = flickr.photos.licenses.getInfo() + license = licenses.find { |l| l.id == info.license } + return { + :title => info.title || "Untitled", + :license_name => license.name, + :license_url => license.url, + :thumbnail_url => FlickRaw.url_q(info), + :fullsize_url => FlickRaw.url_z(info), + :link_url => FlickRaw.url_photopage(info) + } + end - def set_flickr_urls - urls = flickr_urls - self.thumbnail_url = urls[0] - self.fullsize_url = urls[1] + def set_flickr_metadata + self.update_attributes(flickr_metadata) end end diff --git a/app/views/photos/show.html.haml b/app/views/photos/show.html.haml index c27d217f7..912ca5113 100644 --- a/app/views/photos/show.html.haml +++ b/app/views/photos/show.html.haml @@ -3,13 +3,15 @@ = image_tag(@photo.fullsize_url, :alt => 'A plant', :class => 'img-rounded') %p - [Photo title goes here] + = link_to @photo.title, @photo.link_url by - [Flickr username goes here] - on Flickr. - [if licence] - Licensed under [Licence goes here]. - [else] - [Copyright, all rights reserved] - [endif] + = succeed "." do + = link_to @photo.owner, @photo.owner + License: + - if @photo.license_url + = succeed "." do + = link_to @photo.license_name, @photo.license_url + - else + = succeed "." do + = @photo.license_name diff --git a/db/migrate/20130509123711_add_metadata_to_photos.rb b/db/migrate/20130509123711_add_metadata_to_photos.rb new file mode 100644 index 000000000..9e73a6272 --- /dev/null +++ b/db/migrate/20130509123711_add_metadata_to_photos.rb @@ -0,0 +1,22 @@ +class AddMetadataToPhotos < ActiveRecord::Migration + def up + change_table :photos do |t| + t.string :title + t.string :license_name + t.string :license_url + t.string :link_url + t.change :title, :string, :null => false + t.change :license_name, :string, :null => false + t.change :link_url, :string, :null => false + end + end + + def down + change_table :photos do |t| + t.remove :title + t.remove :license_name + t.remove :license_url + t.remove :link_url + end + end +end diff --git a/db/schema.rb b/db/schema.rb index e6810afb1..99a501fb4 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20130508104506) do +ActiveRecord::Schema.define(:version => 20130509123711) do create_table "authentications", :force => true do |t| t.integer "member_id", :null => false @@ -147,6 +147,10 @@ ActiveRecord::Schema.define(:version => 20130508104506) do t.string "fullsize_url", :null => false t.datetime "created_at", :null => false t.datetime "updated_at", :null => false + t.string "title", :null => false + t.string "license_name", :null => false + t.string "license_url" + t.string "link_url", :null => false end create_table "plantings", :force => true do |t| diff --git a/spec/controllers/photos_controller_spec.rb b/spec/controllers/photos_controller_spec.rb index 63a638b1c..c61c7e244 100644 --- a/spec/controllers/photos_controller_spec.rb +++ b/spec/controllers/photos_controller_spec.rb @@ -8,8 +8,11 @@ describe PhotosController do { "owner_id" => "1", "flickr_photo_id" => 1, - "thumbnail_url" => 'http://example.com', - "fullsize_url" => 'http://example.com' + "title" => "Photo", + "license_name" => "CC-BY", + "thumbnail_url" => 'http://example.com/thumb.jpg', + "fullsize_url" => 'http://example.com/full.jpg', + "link_url" => 'http://example.com' } end @@ -60,9 +63,14 @@ describe PhotosController do describe "POST create" do before(:each) do - Photo.any_instance.stub(:flickr_urls).and_return( - ["http://example.com", "http://example.com" ] - ) + Photo.any_instance.stub(:flickr_metadata).and_return( { + :title => "A Heartbreaking work of staggering genius", + :license_name => "CC-BY", + :license_url => "http://example.com/aybpl", + :thumbnail_url => "http://example.com/thumb.jpg", + :fullsize_url => "http://example.com/full.jpg", + :link_url => "http://example.com" + }) end describe "with valid params" do it "creates a new Photo" do diff --git a/spec/factories/photos.rb b/spec/factories/photos.rb index 40f7824b2..70c1fb4fb 100644 --- a/spec/factories/photos.rb +++ b/spec/factories/photos.rb @@ -2,9 +2,18 @@ FactoryGirl.define do factory :photo do - owner_id 1 + owner flickr_photo_id 1 + title "Still life with chillies" + license_name "CC-BY" + license_url "http://example.com/license.html" thumbnail_url "http://example.com/thumb.jpg" fullsize_url "http://example.com/full.jpg" + link_url "http://example.com/" + + factory :unlicensed_photo do + license_name "All rights reserved" + license_url "" + end end end diff --git a/spec/models/photo_spec.rb b/spec/models/photo_spec.rb index 1b8bbfbf8..8ac067ab7 100644 --- a/spec/models/photo_spec.rb +++ b/spec/models/photo_spec.rb @@ -2,13 +2,13 @@ require 'spec_helper' describe Photo do - describe 'generate_flickr_urls' do + describe 'flickr_metadata' do # Any further tests led to us MOCKING ALL THE THINGS # which was epistemologically unsatisfactory. # So we're just going to test that the method exists. it 'exists' do photo = Photo.new(:owner_id => 1) - photo.should.respond_to? :generate_flickr_urls + photo.should.respond_to? :flickr_metadata end end end diff --git a/spec/views/photos/show.html.haml_spec.rb b/spec/views/photos/show.html.haml_spec.rb index a7298fe7c..5b8cebfbf 100644 --- a/spec/views/photos/show.html.haml_spec.rb +++ b/spec/views/photos/show.html.haml_spec.rb @@ -1,12 +1,39 @@ require 'spec_helper' describe "photos/show" do - before(:each) do - @photo = assign(:photo, FactoryGirl.create(:photo)) + context "CC-licensed photo" do + before(:each) do + @photo = assign(:photo, FactoryGirl.create(:photo)) + render + end + + it "shows the image" do + assert_select "img[src=#{@photo.fullsize_url}]" + end + + it "links to the owner's profile" do + assert_select "a", :href => @photo.owner + end + + it "links to the CC license" do + assert_select "a", :href => @photo.license_url, + :text => @photo.license_name + end + + it "shows the title as a link to the original image" do + assert_select "a", :href => @photo.link_url, :text => @photo.title + end end - it "shows the image" do - render - assert_select "img[src=#{@photo.fullsize_url}]" - end + context "unlicensed photo" do + before(:each) do + @photo = assign(:photo, FactoryGirl.create(:unlicensed_photo)) + render + end + + it "contains the phrase 'All rights reserved'" do + rendered.should contain "All rights reserved" + end +end + end From b1b24c432340bd1f70f0b7e4a1f1fc486cdffa5d Mon Sep 17 00:00:00 2001 From: Miles Gould Date: Fri, 31 May 2013 11:28:59 +0100 Subject: [PATCH 14/27] Delete unused photos_helper. --- app/helpers/photos_helper.rb | 2 -- spec/helpers/photos_helper_spec.rb | 15 --------------- 2 files changed, 17 deletions(-) delete mode 100644 app/helpers/photos_helper.rb delete mode 100644 spec/helpers/photos_helper_spec.rb diff --git a/app/helpers/photos_helper.rb b/app/helpers/photos_helper.rb deleted file mode 100644 index 0a10d472b..000000000 --- a/app/helpers/photos_helper.rb +++ /dev/null @@ -1,2 +0,0 @@ -module PhotosHelper -end diff --git a/spec/helpers/photos_helper_spec.rb b/spec/helpers/photos_helper_spec.rb deleted file mode 100644 index c4b452740..000000000 --- a/spec/helpers/photos_helper_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -require 'spec_helper' - -# Specs in this file have access to a helper object that includes -# the PhotosHelper. For example: -# -# describe PhotosHelper do -# describe "string concat" do -# it "concats two strings with spaces" do -# helper.concat_strings("this","that").should == "this that" -# end -# end -# end -describe PhotosHelper do - pending "add some examples to (or delete) #{__FILE__}" -end From b2916e28f3390ac3dff804bb0f8a890d30223d84 Mon Sep 17 00:00:00 2001 From: Miles Gould Date: Fri, 31 May 2013 11:48:24 +0100 Subject: [PATCH 15/27] Don't recreate photos, but update metadata. --- app/controllers/photos_controller.rb | 5 +++-- app/views/photos/show.html.haml | 2 -- spec/controllers/photos_controller_spec.rb | 11 +++++++++++ 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/app/controllers/photos_controller.rb b/app/controllers/photos_controller.rb index 960fd36bc..f20d8ed77 100644 --- a/app/controllers/photos_controller.rb +++ b/app/controllers/photos_controller.rb @@ -46,13 +46,14 @@ class PhotosController < ApplicationController # POST /photos # POST /photos.json def create - @photo = Photo.new(params[:photo]) + @photo = Photo.find_by_flickr_photo_id(params[:photo][:flickr_photo_id]) || + Photo.new(params[:photo]) @photo.owner_id = current_member.id @photo.set_flickr_metadata respond_to do |format| if @photo.save - format.html { redirect_to @photo, notice: 'Photo was successfully created.' } + format.html { redirect_to @photo, notice: 'Photo was successfully added.' } format.json { render json: @photo, status: :created, location: @photo } else format.html { render action: "new" } diff --git a/app/views/photos/show.html.haml b/app/views/photos/show.html.haml index 912ca5113..6306f9994 100644 --- a/app/views/photos/show.html.haml +++ b/app/views/photos/show.html.haml @@ -1,5 +1,3 @@ -%p#notice= notice - = image_tag(@photo.fullsize_url, :alt => 'A plant', :class => 'img-rounded') %p diff --git a/spec/controllers/photos_controller_spec.rb b/spec/controllers/photos_controller_spec.rb index c61c7e244..4355c5bd9 100644 --- a/spec/controllers/photos_controller_spec.rb +++ b/spec/controllers/photos_controller_spec.rb @@ -91,6 +91,17 @@ describe PhotosController do end end + describe "for the second time" do + it "does not add a photo twice" do + expect { + post :create, {:photo => { :flickr_photo_id => 1 } } + }.to change(Photo, :count).by(1) + expect { + post :create, {:photo => { :flickr_photo_id => 1 } } + }.to change(Photo, :count).by(0) + end + end + describe "with invalid params" do it "assigns a newly created but unsaved photo as @photo" do # Trigger the behavior that occurs when invalid params are submitted From 44a236d90d066b92ceed2639a15d58f8f0333858 Mon Sep 17 00:00:00 2001 From: Miles Gould Date: Fri, 31 May 2013 12:05:09 +0100 Subject: [PATCH 16/27] Display all photos on index page. --- app/controllers/photos_controller.rb | 2 +- app/models/photo.rb | 2 ++ app/views/photos/index.html.haml | 43 ++++++++++++----------- spec/views/photos/index.html.haml_spec.rb | 33 +++++++---------- 4 files changed, 38 insertions(+), 42 deletions(-) diff --git a/app/controllers/photos_controller.rb b/app/controllers/photos_controller.rb index f20d8ed77..91680624d 100644 --- a/app/controllers/photos_controller.rb +++ b/app/controllers/photos_controller.rb @@ -3,7 +3,7 @@ class PhotosController < ApplicationController # GET /photos # GET /photos.json def index - @photos = Photo.all + @photos = Photo.paginate(:page => params[:page]) respond_to do |format| format.html # index.html.erb diff --git a/app/models/photo.rb b/app/models/photo.rb index 84b22bcdd..a38d509a0 100644 --- a/app/models/photo.rb +++ b/app/models/photo.rb @@ -3,6 +3,8 @@ class Photo < ActiveRecord::Base :license_url, :thumbnail_url, :fullsize_url, :link_url belongs_to :owner, :class_name => 'Member' + default_scope order("created_at desc") + # This is split into a side-effect free method and a side-effecting method # for easier stubbing and testing. def flickr_metadata diff --git a/app/views/photos/index.html.haml b/app/views/photos/index.html.haml index 3f16c5677..09a8e1bd7 100644 --- a/app/views/photos/index.html.haml +++ b/app/views/photos/index.html.haml @@ -1,25 +1,26 @@ -%h1 Listing photos +- content_for :title, "Photos" -%table - %tr - %th Owner - %th Flickr photo - %th Thumbnail url - %th Fullsize url - %th - %th - %th +%div.pagination + = page_entries_info @photos, :model => "photos" + = will_paginate @photos - - @photos.each do |photo| - %tr - %td= photo.owner_id - %td= photo.flickr_photo_id - %td= photo.thumbnail_url - %td= photo.fullsize_url - %td= link_to 'Show', photo - %td= link_to 'Edit', edit_photo_path(photo) - %td= link_to 'Destroy', photo, :method => :delete, :data => { :confirm => 'Are you sure?' } +- c = 0 +%ul.thumbnails + .row + - @photos.each do |p| + - c += 1 + %li.span2 + .thumbnail(style='height: 220px') + = link_to image_tag(p.thumbnail_url, :alt => p.title, :class => 'img-rounded'), p + %p + = link_to p.title, p + by + = link_to p.owner, p.owner + - if (c % 6) == 0 + .row + +%div.pagination + = page_entries_info @photos, :model => "photos" + = will_paginate @photos -%br -= link_to 'New Photo', new_photo_path diff --git a/spec/views/photos/index.html.haml_spec.rb b/spec/views/photos/index.html.haml_spec.rb index 8dc87e540..bf4699c48 100644 --- a/spec/views/photos/index.html.haml_spec.rb +++ b/spec/views/photos/index.html.haml_spec.rb @@ -2,28 +2,21 @@ require 'spec_helper' describe "photos/index" do before(:each) do - assign(:photos, [ - stub_model(Photo, - :owner_id => 1, - :flickr_photo_id => 2, - :thumbnail_url => "Thumbnail Url", - :fullsize_url => "Fullsize Url" - ), - stub_model(Photo, - :owner_id => 1, - :flickr_photo_id => 2, - :thumbnail_url => "Thumbnail Url", - :fullsize_url => "Fullsize Url" - ) - ]) + page = 1 + per_page = 2 + total_entries = 2 + photos = WillPaginate::Collection.create(page, per_page, total_entries) do |pager| + pager.replace([ + FactoryGirl.create(:photo), + FactoryGirl.create(:photo) + ]) + end + assign(:photos, photos) end - it "renders a list of photos" do + it "renders a gallery of photos" do render - # Run the generator again with the --webrat flag if you want to use webrat matchers - assert_select "tr>td", :text => 1.to_s, :count => 2 - assert_select "tr>td", :text => 2.to_s, :count => 2 - assert_select "tr>td", :text => "Thumbnail Url".to_s, :count => 2 - assert_select "tr>td", :text => "Fullsize Url".to_s, :count => 2 + assert_select ".thumbnail", :count => 2 + assert_select "img", :count => 2 end end From c734f621895d6db7b5a888983b4040a39d18016f Mon Sep 17 00:00:00 2001 From: Miles Gould Date: Fri, 31 May 2013 12:47:21 +0100 Subject: [PATCH 17/27] Plantings HABTM photos. --- app/models/photo.rb | 1 + app/models/planting.rb | 6 ++---- db/migrate/20130531110729_add_photos_plantings_table.rb | 8 ++++++++ db/schema.rb | 7 ++++++- spec/models/planting_spec.rb | 9 +++++++++ 5 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 db/migrate/20130531110729_add_photos_plantings_table.rb diff --git a/app/models/photo.rb b/app/models/photo.rb index a38d509a0..ac67273ab 100644 --- a/app/models/photo.rb +++ b/app/models/photo.rb @@ -2,6 +2,7 @@ class Photo < ActiveRecord::Base attr_accessible :flickr_photo_id, :owner_id, :title, :license_name, :license_url, :thumbnail_url, :fullsize_url, :link_url belongs_to :owner, :class_name => 'Member' + has_and_belongs_to_many :plantings default_scope order("created_at desc") diff --git a/app/models/planting.rb b/app/models/planting.rb index d5c477957..d88668acb 100644 --- a/app/models/planting.rb +++ b/app/models/planting.rb @@ -7,6 +7,7 @@ class Planting < ActiveRecord::Base belongs_to :garden belongs_to :crop + has_and_belongs_to_many :photos default_scope order("created_at desc") @@ -16,6 +17,7 @@ class Planting < ActiveRecord::Base :plantings_count, :to => :crop, :prefix => true + delegate :owner, :to => :garden default_scope order("created_at desc") @@ -33,10 +35,6 @@ class Planting < ActiveRecord::Base return "#{garden.owner.login_name}'s #{garden}" end - def owner - return garden.owner - end - def planted_at_string if planted_at planted_at.strftime("%F") diff --git a/db/migrate/20130531110729_add_photos_plantings_table.rb b/db/migrate/20130531110729_add_photos_plantings_table.rb new file mode 100644 index 000000000..07040ed93 --- /dev/null +++ b/db/migrate/20130531110729_add_photos_plantings_table.rb @@ -0,0 +1,8 @@ +class AddPhotosPlantingsTable < ActiveRecord::Migration + def change + create_table :photos_plantings, :id => false do |t| + t.integer :photo_id + t.integer :planting_id + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 426d275d0..6f99218f9 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20130518002942) do +ActiveRecord::Schema.define(:version => 20130531110729) do create_table "account_types", :force => true do |t| t.string "name", :null => false @@ -171,6 +171,11 @@ ActiveRecord::Schema.define(:version => 20130518002942) do t.string "link_url", :null => false end + create_table "photos_plantings", :id => false, :force => true do |t| + t.integer "photo_id" + t.integer "planting_id" + end + create_table "plantings", :force => true do |t| t.integer "garden_id", :null => false t.integer "crop_id", :null => false diff --git a/spec/models/planting_spec.rb b/spec/models/planting_spec.rb index ca3c67c0c..8a9a75e93 100644 --- a/spec/models/planting_spec.rb +++ b/spec/models/planting_spec.rb @@ -86,4 +86,13 @@ describe Planting do @planting.errors[:sunniness].should include("not valid is not a valid sunniness value") end + context 'photos' do + it 'has a photo' do + @planting = FactoryGirl.create(:planting) + @photo = FactoryGirl.create(:photo) + @planting.photos << @photo + @planting.photos.first.should eq @photo + end + end + end From e072883bb9a4d3a45982fa2cda87785e6c12cbb3 Mon Sep 17 00:00:00 2001 From: Miles Gould Date: Fri, 31 May 2013 13:09:21 +0100 Subject: [PATCH 18/27] Connect plantings to photos. --- app/controllers/photos_controller.rb | 7 +++++++ app/views/photos/new.html.haml | 2 +- app/views/plantings/show.html.haml | 3 +++ spec/controllers/photos_controller_spec.rb | 12 ++++++++++++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/app/controllers/photos_controller.rb b/app/controllers/photos_controller.rb index 91680624d..0280734a1 100644 --- a/app/controllers/photos_controller.rb +++ b/app/controllers/photos_controller.rb @@ -26,6 +26,7 @@ class PhotosController < ApplicationController # GET /photos/new.json def new @photo = Photo.new + @planting_id = params[:planting_id] @flickr_auth = current_member.auth('flickr') if @flickr_auth @@ -50,6 +51,12 @@ class PhotosController < ApplicationController Photo.new(params[:photo]) @photo.owner_id = current_member.id @photo.set_flickr_metadata + if params[:planting_id] + planting = Planting.find_by_id(params[:planting_id]) + if planting + @photo.plantings << planting + end + end respond_to do |format| if @photo.save diff --git a/app/views/photos/new.html.haml b/app/views/photos/new.html.haml index 8bfdc7ab9..ca363dc26 100644 --- a/app/views/photos/new.html.haml +++ b/app/views/photos/new.html.haml @@ -15,7 +15,7 @@ - c += 1 %li.span2 .thumbnail(style='height: 220px') - = link_to image_tag(FlickRaw.url_q(p), :alt => '', :class => 'img-rounded'), photos_path(:photo => { :flickr_photo_id => p.id }), :method => :post + = link_to image_tag(FlickRaw.url_q(p), :alt => '', :class => 'img-rounded'), photos_path(:photo => { :flickr_photo_id => p.id }, :planting_id => @planting_id), :method => :post %p =p.title - if (c % 6) == 0 diff --git a/app/views/plantings/show.html.haml b/app/views/plantings/show.html.haml index f8e375166..f18585951 100644 --- a/app/views/plantings/show.html.haml +++ b/app/views/plantings/show.html.haml @@ -51,6 +51,9 @@ - (1..6).each do .span2 = image_tag('http://placehold.it/150x150', :alt => '', :class => 'img-rounded') +- if can? :create, Photo and can? :edit, @planting + %p + = link_to "Add photo", new_photo_path(:planting_id => @planting.id) %h2 Notes diff --git a/spec/controllers/photos_controller_spec.rb b/spec/controllers/photos_controller_spec.rb index 4355c5bd9..569463c02 100644 --- a/spec/controllers/photos_controller_spec.rb +++ b/spec/controllers/photos_controller_spec.rb @@ -51,6 +51,11 @@ describe PhotosController do get :new, {} assigns(:photo).should be_a_new(Photo) end + + it "assigns a planting id" do + get :new, { :planting_id => 5 } + assigns(:planting_id).should eq "5" + end end describe "GET edit" do @@ -89,6 +94,13 @@ describe PhotosController do post :create, {:photo => { :flickr_photo_id => 1 } } response.should redirect_to(Photo.last) end + + it "attaches the photo to a planting" do + planting = FactoryGirl.create(:planting) + post :create, {:photo => { :flickr_photo_id => 1 }, + :planting_id => planting.id } + Photo.last.plantings.first.should eq planting + end end describe "for the second time" do From d635d58bf1e4cfbc91b07398d05b65b129021afd Mon Sep 17 00:00:00 2001 From: Skud Date: Fri, 31 May 2013 22:56:32 +1000 Subject: [PATCH 19/27] show photos on planting page --- .gitignore | 1 + app/views/plantings/show.html.haml | 30 +++++++++---- db/schema.rb | 47 --------------------- spec/views/plantings/show.html.haml_spec.rb | 18 ++++++++ 4 files changed, 41 insertions(+), 55 deletions(-) diff --git a/.gitignore b/.gitignore index 9b5a1cf4b..7801d8f9e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /log/* +/doc /db/*.sqlite3 /tmp/* .pt diff --git a/app/views/plantings/show.html.haml b/app/views/plantings/show.html.haml index f18585951..a4a3b3a36 100644 --- a/app/views/plantings/show.html.haml +++ b/app/views/plantings/show.html.haml @@ -46,14 +46,28 @@ = pluralize(@planting.crop_plantings_count, "time") by #{Growstuff::Application.config.site_name} members -%h2 Pictures -.row - - (1..6).each do - .span2 - = image_tag('http://placehold.it/150x150', :alt => '', :class => 'img-rounded') -- if can? :create, Photo and can? :edit, @planting - %p - = link_to "Add photo", new_photo_path(:planting_id => @planting.id) +- if @planting.photos.count > 0 or (can? :edit, @planting and can? :create, Photo) + %h2 Pictures + +- c = 0 +%ul.thumbnails + .row + - @planting.photos.each do |p| + - c += 1 + %li.span2 + .thumbnail(style='height: 220px') + = link_to image_tag(p.thumbnail_url, :alt => p.title, :class => 'img-rounded'), p + %p + = link_to p.title, p + by + = link_to p.owner, p.owner + - if (c % 6) == 0 + .row + - if can? :create, Photo and can? :edit, @planting + %li.span2 + .thumbnail(style='height: 220px') + %p{:style => 'text-align: center; padding-top: 50px'} + = link_to "Add photo", new_photo_path(:planting_id => @planting.id), :class => 'btn btn-primary' %h2 Notes diff --git a/db/schema.rb b/db/schema.rb index 6f99218f9..8831606cf 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -13,22 +13,6 @@ ActiveRecord::Schema.define(:version => 20130531110729) do - create_table "account_types", :force => true do |t| - t.string "name", :null => false - t.boolean "is_paid" - t.boolean "is_permanent_paid" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - create_table "accounts", :force => true do |t| - t.integer "member_id", :null => false - t.integer "account_type_id" - t.datetime "paid_until" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - create_table "authentications", :force => true do |t| t.integer "member_id", :null => false t.string "provider", :null => false @@ -137,27 +121,6 @@ ActiveRecord::Schema.define(:version => 20130531110729) do t.datetime "updated_at", :null => false end - create_table "order_items", :force => true do |t| - t.integer "order_id" - t.integer "product_id" - t.integer "price" - t.integer "quantity" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - create_table "orders", :force => true do |t| - t.integer "member_id", :limit => 255, :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.datetime "completed_at" - end - - create_table "orders_products", :id => false, :force => true do |t| - t.integer "order_id" - t.integer "product_id" - end - create_table "photos", :force => true do |t| t.integer "owner_id", :null => false t.integer "flickr_photo_id", :null => false @@ -203,16 +166,6 @@ ActiveRecord::Schema.define(:version => 20130531110729) do add_index "posts", ["created_at", "author_id"], :name => "index_updates_on_created_at_and_user_id" add_index "posts", ["slug"], :name => "index_updates_on_slug", :unique => true - create_table "products", :force => true do |t| - t.string "name", :null => false - t.string "description", :null => false - t.integer "min_price", :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.integer "account_type_id" - t.integer "paid_months" - end - create_table "roles", :force => true do |t| t.string "name", :null => false t.text "description" diff --git a/spec/views/plantings/show.html.haml_spec.rb b/spec/views/plantings/show.html.haml_spec.rb index 414209f1d..71c6c94d1 100644 --- a/spec/views/plantings/show.html.haml_spec.rb +++ b/spec/views/plantings/show.html.haml_spec.rb @@ -29,6 +29,24 @@ describe "plantings/show" do rendered.should_not contain 'sun' end + it "shows photos" do + @member = FactoryGirl.create(:member) + controller.stub(:current_user) { @member } + @p = create_planting_for(@member) + @photo = FactoryGirl.create(:photo, :owner => @member) + @p.photos << @photo + render + assert_select "img[src=#{@photo.thumbnail_url}]" + end + + it "shows a link to add photos" do + @member = FactoryGirl.create(:member) + controller.stub(:current_user) { @member } + @p = create_planting_for(@member) + render + rendered.should contain "Add photo" + end + context "no location set" do before(:each) do controller.stub(:current_user) { nil } From cab7348a3522ebce9cc295fc97050d697ec71540 Mon Sep 17 00:00:00 2001 From: Skud Date: Fri, 31 May 2013 23:13:47 +1000 Subject: [PATCH 20/27] show plantings on photo page --- app/models/planting.rb | 4 +++ app/views/photos/show.html.haml | 37 +++++++++++++++--------- spec/views/photos/show.html.haml_spec.rb | 21 ++++++++++++-- 3 files changed, 46 insertions(+), 16 deletions(-) diff --git a/app/models/planting.rb b/app/models/planting.rb index d88668acb..1535c798b 100644 --- a/app/models/planting.rb +++ b/app/models/planting.rb @@ -46,4 +46,8 @@ class Planting < ActiveRecord::Base def planted_at_string=(str) self.planted_at = str == '' ? nil : Time.parse(str) end + + def to_s + self.crop_system_name + " in " + self.location + end end diff --git a/app/views/photos/show.html.haml b/app/views/photos/show.html.haml index 6306f9994..cde879ecc 100644 --- a/app/views/photos/show.html.haml +++ b/app/views/photos/show.html.haml @@ -1,15 +1,26 @@ -= image_tag(@photo.fullsize_url, :alt => 'A plant', :class => 'img-rounded') +-content_for :title, @photo.title -%p - = link_to @photo.title, @photo.link_url - by - = succeed "." do - = link_to @photo.owner, @photo.owner - License: - - if @photo.license_url - = succeed "." do - = link_to @photo.license_name, @photo.license_url - - else - = succeed "." do - = @photo.license_name +.row + .span6 + %p + %strong Posted by: + = link_to @photo.owner, @photo.owner + %p + %strong License: + - if @photo.license_url + = link_to @photo.license_name, @photo.license_url + - else + = succeed "." do + = @photo.license_name + %p + = link_to "View on Flickr", @photo.link_url + + .span6 + - if @photo.plantings.count > 0 + %p This photo depicts: + %ul + - @photo.plantings.each do |p| + %li= link_to p, p + +%p= image_tag(@photo.fullsize_url, :alt => 'A plant', :class => 'img-rounded') diff --git a/spec/views/photos/show.html.haml_spec.rb b/spec/views/photos/show.html.haml_spec.rb index 5b8cebfbf..fa03e08d6 100644 --- a/spec/views/photos/show.html.haml_spec.rb +++ b/spec/views/photos/show.html.haml_spec.rb @@ -20,8 +20,8 @@ describe "photos/show" do :text => @photo.license_name end - it "shows the title as a link to the original image" do - assert_select "a", :href => @photo.link_url, :text => @photo.title + it "shows a link to the original image" do + assert_select "a", :href => @photo.link_url, :text => "View on Flickr" end end @@ -34,6 +34,21 @@ describe "photos/show" do it "contains the phrase 'All rights reserved'" do rendered.should contain "All rights reserved" end -end + end + + context "linked to a planting" do + before(:each) do + @photo = FactoryGirl.create(:photo) + @planting = FactoryGirl.create(:planting) + @planting.photos << @photo + @photo = assign(:photo, @photo) + render + end + + it "shows link to planting" do + assert_select "a[href=#{planting_path(@planting)}]" + end + + end end From c63eb64565064ddbefbe2ec48166e32e518797dc Mon Sep 17 00:00:00 2001 From: Skud Date: Fri, 31 May 2013 23:35:07 +1000 Subject: [PATCH 21/27] photo and planting owners must match --- app/controllers/photos_controller.rb | 9 +++++- spec/controllers/photos_controller_spec.rb | 32 ++++++++++++++++++++-- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/app/controllers/photos_controller.rb b/app/controllers/photos_controller.rb index 0280734a1..41348cb1e 100644 --- a/app/controllers/photos_controller.rb +++ b/app/controllers/photos_controller.rb @@ -51,10 +51,17 @@ class PhotosController < ApplicationController Photo.new(params[:photo]) @photo.owner_id = current_member.id @photo.set_flickr_metadata + if params[:planting_id] planting = Planting.find_by_id(params[:planting_id]) if planting - @photo.plantings << planting + if planting.owner.id == current_member.id + @photo.plantings << planting + else + flash[:alert] = "You must own both the planting and the photo." + end + else + flash[:alert] = "Couldn't find planting to connect to photo." end end diff --git a/spec/controllers/photos_controller_spec.rb b/spec/controllers/photos_controller_spec.rb index 569463c02..efb7a651d 100644 --- a/spec/controllers/photos_controller_spec.rb +++ b/spec/controllers/photos_controller_spec.rb @@ -96,8 +96,12 @@ describe PhotosController do end it "attaches the photo to a planting" do - planting = FactoryGirl.create(:planting) - post :create, {:photo => { :flickr_photo_id => 1 }, + member = FactoryGirl.create(:member) + controller.stub(:current_member) { member } + garden = FactoryGirl.create(:garden, :owner => member) + planting = FactoryGirl.create(:planting, :garden => garden) + photo = FactoryGirl.create(:photo, :owner => member) + post :create, {:photo => { :flickr_photo_id => photo.flickr_photo_id }, :planting_id => planting.id } Photo.last.plantings.first.should eq planting end @@ -114,6 +118,30 @@ describe PhotosController do end end + describe "with matching owners" do + it "creates the planting/photo link" do + member = FactoryGirl.create(:member) + controller.stub(:current_member) { member } + garden = FactoryGirl.create(:garden, :owner => member) + planting = FactoryGirl.create(:planting, :garden => garden) + photo = FactoryGirl.create(:photo, :owner => member) + post :create, {:photo => { :flickr_photo_id => photo.flickr_photo_id }, + :planting_id => planting.id } + Photo.last.plantings.first.should eq planting + end + end + + describe "with mismatched owners" do + it "creates the planting/photo link" do + # members will be auto-created, and different + planting = FactoryGirl.create(:planting) + photo = FactoryGirl.create(:photo) + post :create, {:photo => { :flickr_photo_id => photo.flickr_photo_id }, + :planting_id => planting.id } + Photo.last.plantings.first.should_not eq planting + end + end + describe "with invalid params" do it "assigns a newly created but unsaved photo as @photo" do # Trigger the behavior that occurs when invalid params are submitted From cd111f4cc24886b2bf5752d7c9393b3c67a84b0c Mon Sep 17 00:00:00 2001 From: Skud Date: Fri, 31 May 2013 23:37:48 +1000 Subject: [PATCH 22/27] added alt tag --- app/views/photos/show.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/photos/show.html.haml b/app/views/photos/show.html.haml index cde879ecc..47a2b7ecc 100644 --- a/app/views/photos/show.html.haml +++ b/app/views/photos/show.html.haml @@ -22,5 +22,5 @@ - @photo.plantings.each do |p| %li= link_to p, p -%p= image_tag(@photo.fullsize_url, :alt => 'A plant', :class => 'img-rounded') +%p= image_tag(@photo.fullsize_url, :alt => @photo.title, :class => 'img-rounded') From 77bb0080836e460676ec0088d9351c133299fa0d Mon Sep 17 00:00:00 2001 From: Skud Date: Sat, 1 Jun 2013 11:21:17 +1000 Subject: [PATCH 23/27] changed flickr_photo_id to string ... because integer worked fine in dev (on sqlite3) but broke on staging (with postgres). Turns out flickr photo IDs are quite LARGE integers. But really they could be anything, so string seems safest. --- .../20130601011725_change_flickr_photo_id_to_string.rb | 8 ++++++++ db/schema.rb | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20130601011725_change_flickr_photo_id_to_string.rb diff --git a/db/migrate/20130601011725_change_flickr_photo_id_to_string.rb b/db/migrate/20130601011725_change_flickr_photo_id_to_string.rb new file mode 100644 index 000000000..2dd847ac4 --- /dev/null +++ b/db/migrate/20130601011725_change_flickr_photo_id_to_string.rb @@ -0,0 +1,8 @@ +class ChangeFlickrPhotoIdToString < ActiveRecord::Migration + def up + change_column :photos, :flickr_photo_id, :string + end + def down + change_column :photos, :flickr_photo_id, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index 8831606cf..6e91ac8cb 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20130531110729) do +ActiveRecord::Schema.define(:version => 20130601011725) do create_table "authentications", :force => true do |t| t.integer "member_id", :null => false @@ -123,7 +123,7 @@ ActiveRecord::Schema.define(:version => 20130531110729) do create_table "photos", :force => true do |t| t.integer "owner_id", :null => false - t.integer "flickr_photo_id", :null => false + t.string "flickr_photo_id", :null => false t.string "thumbnail_url", :null => false t.string "fullsize_url", :null => false t.datetime "created_at", :null => false From 10fdabfe3715d40fc4888612fcf08975493ef550 Mon Sep 17 00:00:00 2001 From: Skud Date: Sat, 1 Jun 2013 11:32:49 +1000 Subject: [PATCH 24/27] rearranged notes/pics on plantings page --- app/views/plantings/show.html.haml | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/app/views/plantings/show.html.haml b/app/views/plantings/show.html.haml index a4a3b3a36..137ffaaa4 100644 --- a/app/views/plantings/show.html.haml +++ b/app/views/plantings/show.html.haml @@ -46,6 +46,16 @@ = pluralize(@planting.crop_plantings_count, "time") by #{Growstuff::Application.config.site_name} members +%h2 + Notes + +:markdown + #{ @planting.description != "" ? @planting.description : "No description given." } + +- if can? :edit, @planting + = link_to 'Edit', edit_planting_path(@planting), :class => 'btn btn-mini' + + - if @planting.photos.count > 0 or (can? :edit, @planting and can? :create, Photo) %h2 Pictures @@ -68,12 +78,3 @@ .thumbnail(style='height: 220px') %p{:style => 'text-align: center; padding-top: 50px'} = link_to "Add photo", new_photo_path(:planting_id => @planting.id), :class => 'btn btn-primary' - -%h2 - Notes - -:markdown - #{ @planting.description != "" ? @planting.description : "No description given." } - -- if can? :edit, @planting - = link_to 'Edit', edit_planting_path(@planting), :class => 'btn btn-mini' From 6ecbf749eb2845a27e5a3a948bc14b15a2358c51 Mon Sep 17 00:00:00 2001 From: Skud Date: Sat, 1 Jun 2013 12:07:17 +1000 Subject: [PATCH 25/27] Avoid duplicate photos on plantings (or vice versa) Strictly speaking this doesn't prevent you adding them if you really try, but the validation for that was beyond what I could figure out (the docs don't help, and all SO/blog posts are outdated and didn't work). However, if you do somehow manage to add dups, you will never see them again thanks to the :uniq => true in the model. That's good enough for me. --- app/controllers/photos_controller.rb | 2 +- app/models/photo.rb | 2 +- app/models/planting.rb | 2 +- spec/controllers/photos_controller_spec.rb | 14 ++++++++++++++ spec/models/planting_spec.rb | 8 ++++++++ 5 files changed, 25 insertions(+), 3 deletions(-) diff --git a/app/controllers/photos_controller.rb b/app/controllers/photos_controller.rb index 41348cb1e..f9d6bf4c5 100644 --- a/app/controllers/photos_controller.rb +++ b/app/controllers/photos_controller.rb @@ -56,7 +56,7 @@ class PhotosController < ApplicationController planting = Planting.find_by_id(params[:planting_id]) if planting if planting.owner.id == current_member.id - @photo.plantings << planting + @photo.plantings << planting unless @photo.plantings.include?(planting) else flash[:alert] = "You must own both the planting and the photo." end diff --git a/app/models/photo.rb b/app/models/photo.rb index ac67273ab..81e0029c8 100644 --- a/app/models/photo.rb +++ b/app/models/photo.rb @@ -2,7 +2,7 @@ class Photo < ActiveRecord::Base attr_accessible :flickr_photo_id, :owner_id, :title, :license_name, :license_url, :thumbnail_url, :fullsize_url, :link_url belongs_to :owner, :class_name => 'Member' - has_and_belongs_to_many :plantings + has_and_belongs_to_many :plantings, :uniq => true default_scope order("created_at desc") diff --git a/app/models/planting.rb b/app/models/planting.rb index 1535c798b..cf31a82b3 100644 --- a/app/models/planting.rb +++ b/app/models/planting.rb @@ -7,7 +7,7 @@ class Planting < ActiveRecord::Base belongs_to :garden belongs_to :crop - has_and_belongs_to_many :photos + has_and_belongs_to_many :photos, :uniq => true default_scope order("created_at desc") diff --git a/spec/controllers/photos_controller_spec.rb b/spec/controllers/photos_controller_spec.rb index efb7a651d..d31edabc4 100644 --- a/spec/controllers/photos_controller_spec.rb +++ b/spec/controllers/photos_controller_spec.rb @@ -56,6 +56,7 @@ describe PhotosController do get :new, { :planting_id => 5 } assigns(:planting_id).should eq "5" end + end describe "GET edit" do @@ -105,6 +106,19 @@ describe PhotosController do :planting_id => planting.id } Photo.last.plantings.first.should eq planting end + + it "doesn't attach a photo to a planting twice" do + member = FactoryGirl.create(:member) + controller.stub(:current_member) { member } + garden = FactoryGirl.create(:garden, :owner => member) + planting = FactoryGirl.create(:planting, :garden => garden) + photo = FactoryGirl.create(:photo, :owner => member) + post :create, {:photo => { :flickr_photo_id => photo.flickr_photo_id }, + :planting_id => planting.id } + post :create, {:photo => { :flickr_photo_id => photo.flickr_photo_id }, + :planting_id => planting.id } + Photo.last.plantings.count.should eq 1 + end end describe "for the second time" do diff --git a/spec/models/planting_spec.rb b/spec/models/planting_spec.rb index 8a9a75e93..bb0838c9d 100644 --- a/spec/models/planting_spec.rb +++ b/spec/models/planting_spec.rb @@ -93,6 +93,14 @@ describe Planting do @planting.photos << @photo @planting.photos.first.should eq @photo end + + it "doesn't return duplicate photos" do + @planting = FactoryGirl.create(:planting) + @photo = FactoryGirl.create(:photo) + @planting.photos << @photo + @planting.photos << @photo + @planting.photos.count.should eq 1 + end end end From 2a301d352bd0f7439782a5f3cb9c026a989101b9 Mon Sep 17 00:00:00 2001 From: Skud Date: Sat, 1 Jun 2013 12:25:43 +1000 Subject: [PATCH 26/27] Reverted uniqueness limits for photo/planting association It seems this interacts badly with the default_scope on postgres (but not on sqlite3). Error message from the logs: 2013-06-01T02:21:05.312099+00:00 app[web.1]: ActiveRecord::StatementInvalid (PG::Error: ERROR: for SELECT DISTINCT, ORDER BY expressions must appear in select list 2013-06-01T02:21:05.312099+00:00 app[web.1]: LINE 1: ...photo_id" = 2 AND "plantings"."id" = 181 ORDER BY created_at... 2013-06-01T02:21:05.312099+00:00 app[web.1]: app/controllers/photos_controller.rb:59:in `create' 2013-06-01T02:21:05.312099+00:00 app[web.1]: ^ 2013-06-01T02:21:05.312099+00:00 app[web.1]: : SELECT DISTINCT 1 AS one FROM "plantings" INNER JOIN "photos_plantings" ON "plantings"."id" = "photos_plantings"."planting_id" WHERE "photos_plantings"."photo_id" = 2 AND "plantings"."id" = 181 ORDER BY created_at desc LIMIT 1): For now, we'll just have to rely on the controller (which adds the association) to keep things unique. --- app/models/photo.rb | 2 +- app/models/planting.rb | 2 +- spec/models/planting_spec.rb | 8 -------- 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/app/models/photo.rb b/app/models/photo.rb index 81e0029c8..ac67273ab 100644 --- a/app/models/photo.rb +++ b/app/models/photo.rb @@ -2,7 +2,7 @@ class Photo < ActiveRecord::Base attr_accessible :flickr_photo_id, :owner_id, :title, :license_name, :license_url, :thumbnail_url, :fullsize_url, :link_url belongs_to :owner, :class_name => 'Member' - has_and_belongs_to_many :plantings, :uniq => true + has_and_belongs_to_many :plantings default_scope order("created_at desc") diff --git a/app/models/planting.rb b/app/models/planting.rb index cf31a82b3..1535c798b 100644 --- a/app/models/planting.rb +++ b/app/models/planting.rb @@ -7,7 +7,7 @@ class Planting < ActiveRecord::Base belongs_to :garden belongs_to :crop - has_and_belongs_to_many :photos, :uniq => true + has_and_belongs_to_many :photos default_scope order("created_at desc") diff --git a/spec/models/planting_spec.rb b/spec/models/planting_spec.rb index bb0838c9d..8a9a75e93 100644 --- a/spec/models/planting_spec.rb +++ b/spec/models/planting_spec.rb @@ -93,14 +93,6 @@ describe Planting do @planting.photos << @photo @planting.photos.first.should eq @photo end - - it "doesn't return duplicate photos" do - @planting = FactoryGirl.create(:planting) - @photo = FactoryGirl.create(:photo) - @planting.photos << @photo - @planting.photos << @photo - @planting.photos.count.should eq 1 - end end end From 5ba023ad011688563892f1f87d64ad9a4e906e8f Mon Sep 17 00:00:00 2001 From: Skud Date: Mon, 3 Jun 2013 14:34:29 +1000 Subject: [PATCH 27/27] added deploy tasks script --- script/deploy-tasks.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100755 script/deploy-tasks.sh diff --git a/script/deploy-tasks.sh b/script/deploy-tasks.sh new file mode 100755 index 000000000..dc18a2390 --- /dev/null +++ b/script/deploy-tasks.sh @@ -0,0 +1,14 @@ +# tasks to run at deploy time, usually after 'rake db:migrate' + +# When adding tasks, do so in chronological order, and note the date +# when it was added. This will help us know which ones have been run +# and can safely be commented out or removed. + +echo "2013-05-?? - Replacing empty post/notification subjects with '(no subject)'" +rake growstuff:oneoff:empty_subjects + +echo "2013-06-03 - replace empty garden names with 'Garden'" +rake growstuff:oneoff:empty_garden_names + + +