From a2fab25a37dbf7ab4ee43f06793cf51023164384 Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Fri, 22 Feb 2013 10:40:33 +0000 Subject: [PATCH 01/32] Bump rails version to 3.2.12 --- Gemfile | 2 +- Gemfile.lock | 93 ++++++++++++++++++++++++++-------------------------- 2 files changed, 48 insertions(+), 47 deletions(-) diff --git a/Gemfile b/Gemfile index 263215e..a7e2769 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' -gem 'rails', '3.2.11' +gem 'rails', '3.2.12' # Bundle edge Rails instead: # gem 'rails', :git => 'git://github.com/rails/rails.git' diff --git a/Gemfile.lock b/Gemfile.lock index 590cffc..72ae3f3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,38 +1,38 @@ GEM remote: https://rubygems.org/ specs: - actionmailer (3.2.11) - actionpack (= 3.2.11) + actionmailer (3.2.12) + actionpack (= 3.2.12) mail (~> 2.4.4) - actionpack (3.2.11) - activemodel (= 3.2.11) - activesupport (= 3.2.11) + actionpack (3.2.12) + activemodel (= 3.2.12) + activesupport (= 3.2.12) builder (~> 3.0.0) erubis (~> 2.7.0) journey (~> 1.0.4) - rack (~> 1.4.0) + rack (~> 1.4.5) rack-cache (~> 1.2) rack-test (~> 0.6.1) sprockets (~> 2.2.1) - activemodel (3.2.11) - activesupport (= 3.2.11) + activemodel (3.2.12) + activesupport (= 3.2.12) builder (~> 3.0.0) - activerecord (3.2.11) - activemodel (= 3.2.11) - activesupport (= 3.2.11) + activerecord (3.2.12) + activemodel (= 3.2.12) + activesupport (= 3.2.12) arel (~> 3.0.2) tzinfo (~> 0.3.29) - activeresource (3.2.11) - activemodel (= 3.2.11) - activesupport (= 3.2.11) - activesupport (3.2.11) + activeresource (3.2.12) + activemodel (= 3.2.12) + activesupport (= 3.2.12) + activesupport (3.2.12) i18n (~> 0.6) multi_json (~> 1.0) arel (3.0.2) bcrypt-ruby (3.0.1) - bson (1.8.1) - bson_ext (1.8.1) - bson (~> 1.8.1) + bson (1.8.2) + bson_ext (1.8.2) + bson (~> 1.8.2) builder (3.0.4) coffee-rails (3.2.2) coffee-script (>= 2.2.0) @@ -45,7 +45,7 @@ GEM erubis (2.7.0) execjs (1.4.0) multi_json (~> 1.0) - faraday (0.8.4) + faraday (0.8.5) multipart-post (~> 1.1) feedzirra (0.0.31) activesupport (>= 3.0.8) @@ -57,21 +57,22 @@ GEM rake (>= 0.9.2) rdoc (~> 3.8) sax-machine (~> 0.0.20) - haml (3.1.7) - haml-rails (0.3.5) + haml (4.0.0) + tilt + haml-rails (0.4) actionpack (>= 3.1, < 4.1) activesupport (>= 3.1, < 4.1) - haml (~> 3.1) + haml (>= 3.1, < 4.1) railties (>= 3.1, < 4.1) hike (1.2.1) htmlentities (4.3.1) httpauth (0.2.0) i18n (0.6.1) journey (1.0.4) - jquery-rails (2.1.4) + jquery-rails (2.2.1) railties (>= 3.0, < 5.0) thor (>= 0.14, < 2.0) - json (1.7.6) + json (1.7.7) jwt (0.1.5) multi_json (>= 1.0) loofah (1.0.0) @@ -80,21 +81,21 @@ GEM i18n (>= 0.4.0) mime-types (~> 1.16) treetop (~> 1.4.8) - mime-types (1.19) + mime-types (1.21) mm-multi-parameter-attributes (0.2.2) mongo_mapper (>= 0.9.0) tzinfo - mongo (1.8.1) - bson (~> 1.8.1) + mongo (1.8.2) + bson (~> 1.8.2) mongo_mapper (0.12.0) activemodel (~> 3.0) activesupport (~> 3.0) plucky (~> 0.5.2) - multi_json (1.5.0) + multi_json (1.6.1) multipart-post (1.1.5) nokogiri (1.4.7) oauth (0.4.7) - oauth2 (0.8.0) + oauth2 (0.8.1) faraday (~> 0.8) httpauth (~> 0.1) jwt (~> 0.1.4) @@ -103,39 +104,39 @@ GEM plucky (0.5.2) mongo (~> 1.5) polyglot (0.3.3) - rack (1.4.4) + rack (1.4.5) rack-cache (1.2) rack (>= 0.4) - rack-ssl (1.3.2) + rack-ssl (1.3.3) rack rack-test (0.6.2) rack (>= 1.0) - rails (3.2.11) - actionmailer (= 3.2.11) - actionpack (= 3.2.11) - activerecord (= 3.2.11) - activeresource (= 3.2.11) - activesupport (= 3.2.11) + rails (3.2.12) + actionmailer (= 3.2.12) + actionpack (= 3.2.12) + activerecord (= 3.2.12) + activeresource (= 3.2.12) + activesupport (= 3.2.12) bundler (~> 1.0) - railties (= 3.2.11) - railties (3.2.11) - actionpack (= 3.2.11) - activesupport (= 3.2.11) + railties (= 3.2.12) + railties (3.2.12) + actionpack (= 3.2.12) + activesupport (= 3.2.12) rack-ssl (~> 1.3.2) rake (>= 0.8.7) rdoc (~> 3.4) thor (>= 0.14.6, < 2.0) rake (10.0.3) - rdoc (3.12) + rdoc (3.12.1) json (~> 1.4) sass (3.2.5) - sass-rails (3.2.5) + sass-rails (3.2.6) railties (~> 3.2.0) sass (>= 3.1.10) tilt (~> 1.3) sax-machine (0.0.20) nokogiri (> 0.0.0) - sorcery (0.8.0) + sorcery (0.8.1) bcrypt-ruby (~> 3.0.0) oauth (~> 0.4.4) oauth2 (~> 0.8.0) @@ -144,7 +145,7 @@ GEM multi_json (~> 1.0) rack (~> 1.0) tilt (~> 1.1, != 1.3.0) - thor (0.16.0) + thor (0.17.0) tilt (1.3.3) treetop (1.4.12) polyglot @@ -167,7 +168,7 @@ DEPENDENCIES jquery-rails mm-multi-parameter-attributes mongo_mapper - rails (= 3.2.11) + rails (= 3.2.12) sass-rails (~> 3.2.3) sorcery uglifier (>= 1.0.3) From d45dbb4e763700c70301a4399fba212d956c21a9 Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Fri, 22 Feb 2013 10:44:06 +0000 Subject: [PATCH 02/32] Remove MongoMapper gems; add Postgres gems --- Gemfile | 10 ++-------- Gemfile.lock | 22 +++++----------------- 2 files changed, 7 insertions(+), 25 deletions(-) diff --git a/Gemfile b/Gemfile index a7e2769..ac935b7 100644 --- a/Gemfile +++ b/Gemfile @@ -2,11 +2,6 @@ source 'https://rubygems.org' gem 'rails', '3.2.12' -# Bundle edge Rails instead: -# gem 'rails', :git => 'git://github.com/rails/rails.git' - - - # Gems used only for assets and not required # in production environments by default. group :assets do @@ -36,11 +31,10 @@ gem 'jquery-rails' # To use debugger # gem 'debugger' -gem 'mongo_mapper' -gem 'bson_ext' gem 'haml-rails' -gem 'mm-multi-parameter-attributes' gem 'feedzirra' gem 'htmlentities' gem 'sorcery' gem 'will_paginate', '~> 3.0' +gem 'activerecord-postgresql-adapter' +gem 'pg' diff --git a/Gemfile.lock b/Gemfile.lock index 72ae3f3..2168b8f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -22,6 +22,8 @@ GEM activesupport (= 3.2.12) arel (~> 3.0.2) tzinfo (~> 0.3.29) + activerecord-postgresql-adapter (0.0.1) + pg activeresource (3.2.12) activemodel (= 3.2.12) activesupport (= 3.2.12) @@ -30,9 +32,6 @@ GEM multi_json (~> 1.0) arel (3.0.2) bcrypt-ruby (3.0.1) - bson (1.8.2) - bson_ext (1.8.2) - bson (~> 1.8.2) builder (3.0.4) coffee-rails (3.2.2) coffee-script (>= 2.2.0) @@ -82,15 +81,6 @@ GEM mime-types (~> 1.16) treetop (~> 1.4.8) mime-types (1.21) - mm-multi-parameter-attributes (0.2.2) - mongo_mapper (>= 0.9.0) - tzinfo - mongo (1.8.2) - bson (~> 1.8.2) - mongo_mapper (0.12.0) - activemodel (~> 3.0) - activesupport (~> 3.0) - plucky (~> 0.5.2) multi_json (1.6.1) multipart-post (1.1.5) nokogiri (1.4.7) @@ -101,8 +91,7 @@ GEM jwt (~> 0.1.4) multi_json (~> 1.0) rack (~> 1.2) - plucky (0.5.2) - mongo (~> 1.5) + pg (0.14.1) polyglot (0.3.3) rack (1.4.5) rack-cache (1.2) @@ -160,14 +149,13 @@ PLATFORMS ruby DEPENDENCIES - bson_ext + activerecord-postgresql-adapter coffee-rails (~> 3.2.1) feedzirra haml-rails htmlentities jquery-rails - mm-multi-parameter-attributes - mongo_mapper + pg rails (= 3.2.12) sass-rails (~> 3.2.3) sorcery From 8f01d8e1d6719ba0e9d58161dd26204d990e54c6 Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Fri, 22 Feb 2013 10:52:09 +0000 Subject: [PATCH 03/32] Remove mongo config; add postgres config --- config/database.yml | 26 ++++++++++++++++++++++++++ config/mongo.yml | 15 --------------- 2 files changed, 26 insertions(+), 15 deletions(-) create mode 100644 config/database.yml delete mode 100644 config/mongo.yml diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..4904f45 --- /dev/null +++ b/config/database.yml @@ -0,0 +1,26 @@ +development: + adapter: postgresql + encoding: unicode + database: apollo_development + pool: 5 + username: postgres + password: + port: 5433 + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: + adapter: postgresql + encoding: unicode + database: apollo_test + pool: 5 + username: postgres + password: + port: 5433 + +production: + adapter: sqlite3 + database: db/production.sqlite3 + pool: 5 + timeout: 5000 diff --git a/config/mongo.yml b/config/mongo.yml deleted file mode 100644 index 5f11e48..0000000 --- a/config/mongo.yml +++ /dev/null @@ -1,15 +0,0 @@ -defaults: &defaults - host: 127.0.0.1 - port: 27017 - -development: - <<: *defaults - database: apollo_development - -test: - <<: *defaults - database: apollo_test - -# set these environment variables on your prod server -production: - uri: <%= ENV['MONGOLAB_URI'] %> From 9c6819ad01f6ac069440bcb016e2da633e7f2fa7 Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Fri, 22 Feb 2013 10:52:26 +0000 Subject: [PATCH 04/32] Remove mongo ORM config --- config/application.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/config/application.rb b/config/application.rb index 426326e..69a830a 100644 --- a/config/application.rb +++ b/config/application.rb @@ -15,7 +15,6 @@ if defined?(Bundler) # Bundler.require(:default, :assets, Rails.env) end - module Apollo class Application < Rails::Application config.action_mailer.default_url_options = { :host => ENV['APOLLO_HOSTNAME'] } @@ -72,9 +71,7 @@ module Apollo # http://mongomapper.com/documentation/getting-started/rails.html config.generators do |g| g.template_engine :haml - g.orm :mongo_mapper end - MongoMapper::Document.plugin(MongoMapper::Plugins::MultiParameterAttributes) # Time.zone = 'London' end From 8dcb0ecbf4f7ffb28252bc5acafa8a840858fc94 Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Fri, 22 Feb 2013 11:06:28 +0000 Subject: [PATCH 05/32] Activate all rails frameworks --- config/application.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/config/application.rb b/config/application.rb index 69a830a..57fa486 100644 --- a/config/application.rb +++ b/config/application.rb @@ -1,12 +1,13 @@ require File.expand_path('../boot', __FILE__) # Pick the frameworks you want: +require 'rails/all' # require "active_record/railtie" -require "action_controller/railtie" -require "action_mailer/railtie" -require "active_resource/railtie" -require "sprockets/railtie" -require "rails/test_unit/railtie" +# require "action_controller/railtie" +# require "action_mailer/railtie" +# require "active_resource/railtie" +# require "sprockets/railtie" +# require "rails/test_unit/railtie" if defined?(Bundler) # If you precompile assets before deploying to production, use this line @@ -72,7 +73,6 @@ module Apollo config.generators do |g| g.template_engine :haml end - MongoMapper::Document.plugin(MongoMapper::Plugins::MultiParameterAttributes) # Time.zone = 'London' end end From 38390089bacc847d6636d96525d5b56b8653aa9d Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Fri, 22 Feb 2013 11:16:55 +0000 Subject: [PATCH 06/32] Add schema for feeds and posts --- db/schema.rb | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 db/schema.rb diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..530daa7 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,42 @@ +# encoding: UTF-8 +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). +# +# It's strongly recommended to check this file into your version control system. + +ActiveRecord::Schema.define(:version => 20130213220036) do + + create_table "feeds", :force => true do |t| + t.string "title" + t.string "feed_url" + t.string "url" + t.string "description" + t.string "guid" + t.string "generator" + t.time "last_fetched" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "posts", :force => true do |t| + t.string "title" + t.string "url" + t.string "author" + t.text "summary" + t.text "content" + t.time "published" + t.decimal "lat" + t.decimal "lon" + t.integer "feed_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + +end From 1dacc2d690c577eec9d99171c6ea4217279727d7 Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Fri, 22 Feb 2013 11:23:14 +0000 Subject: [PATCH 07/32] Add users table --- db/migrate/20130222112030_sorcery_core.rb | 16 ++++++++++++++++ db/schema.rb | 11 ++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20130222112030_sorcery_core.rb diff --git a/db/migrate/20130222112030_sorcery_core.rb b/db/migrate/20130222112030_sorcery_core.rb new file mode 100644 index 0000000..24956fe --- /dev/null +++ b/db/migrate/20130222112030_sorcery_core.rb @@ -0,0 +1,16 @@ +class SorceryCore < ActiveRecord::Migration + def self.up + create_table :users do |t| + t.string :username, :null => false # if you use another field as a username, for example email, you can safely remove this field. + t.string :email, :default => nil # if you use this field as a username, you might want to make it :null => false. + t.string :crypted_password, :default => nil + t.string :salt, :default => nil + + t.timestamps + end + end + + def self.down + drop_table :users + end +end \ No newline at end of file diff --git a/db/schema.rb b/db/schema.rb index 530daa7..8cc6775 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 => 20130213220036) do +ActiveRecord::Schema.define(:version => 20130222112030) do create_table "feeds", :force => true do |t| t.string "title" @@ -39,4 +39,13 @@ ActiveRecord::Schema.define(:version => 20130213220036) do t.datetime "updated_at", :null => false end + create_table "users", :force => true do |t| + t.string "username", :null => false + t.string "email" + t.string "crypted_password" + t.string "salt" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + end From 370d27655ee1639a56065d81464d988fcb23c701 Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Fri, 22 Feb 2013 11:26:12 +0000 Subject: [PATCH 08/32] Remove MongoMapper config from models --- app/models/feed.rb | 15 +-------------- app/models/post.rb | 13 ------------- app/models/user.rb | 8 -------- 3 files changed, 1 insertion(+), 35 deletions(-) diff --git a/app/models/feed.rb b/app/models/feed.rb index 2838749..f3dcf0e 100644 --- a/app/models/feed.rb +++ b/app/models/feed.rb @@ -1,18 +1,5 @@ class Feed - include MongoMapper::Document - - key :title, String, :default => "[New feed - hasn't been fetched yet]" - key :feed_url, String # The URL of the RSS feed, not the website that owns it - key :url, String # The URL of website. Called "link" in RSS 2.0 - key :description, String - key :guid, String # Atom id or RSS guid - key :generator, String - key :last_fetched, Time, :default => nil - timestamps! - - ensure_index :title - - many :posts, :dependent => :destroy + has_many :posts, :dependent => :destroy validates :title, :presence => true validates_format_of :feed_url, :with => URI::regexp(%w(http https)), :message => "must be a valid URL" diff --git a/app/models/post.rb b/app/models/post.rb index 3841336..f5799b4 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -1,17 +1,4 @@ class Post - include MongoMapper::Document - - key :title, String - key :url, String - key :author, String - key :summary, String - key :content, String - key :published, Time - key :loc, Hash # { lng, lat } - timestamps! - - ensure_index [[:loc, '2d']] - belongs_to :feed EARTH_RADIUS_M = 6378000 diff --git a/app/models/user.rb b/app/models/user.rb index 4eeb5b4..27c786f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,11 +1,4 @@ class User - include MongoMapper::Document - - key :email, String - key :crypted_password, String - key :salt, String - timestamps! - authenticates_with_sorcery! # attr_accessible :email, :password, :password_confirmation @@ -14,5 +7,4 @@ class User validates_uniqueness_of :email validates_length_of :password, :minimum => 3, :message => "password must be at least 3 characters long", :if => :password validates_confirmation_of :password, :message => "should match confirmation", :if => :password - end From f5a0f586c7b96054196583f9cfe597d62d2e3c86 Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Fri, 22 Feb 2013 11:28:16 +0000 Subject: [PATCH 09/32] Add ActiveRecord subclassing --- app/models/feed.rb | 2 +- app/models/post.rb | 2 +- app/models/user.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/models/feed.rb b/app/models/feed.rb index f3dcf0e..9271d1f 100644 --- a/app/models/feed.rb +++ b/app/models/feed.rb @@ -1,4 +1,4 @@ -class Feed +class Feed < ActiveRecord::Base has_many :posts, :dependent => :destroy validates :title, :presence => true diff --git a/app/models/post.rb b/app/models/post.rb index f5799b4..73fe0d4 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -1,4 +1,4 @@ -class Post +class Post < ActiveRecord::Base belongs_to :feed EARTH_RADIUS_M = 6378000 diff --git a/app/models/user.rb b/app/models/user.rb index 27c786f..1afe6a4 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,4 +1,4 @@ -class User +class User < ActiveRecord::Base authenticates_with_sorcery! # attr_accessible :email, :password, :password_confirmation From dca7e74aae12d4d23b1c954cd3e23f078b09ab94 Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Fri, 22 Feb 2013 11:36:11 +0000 Subject: [PATCH 10/32] Add meta_request gem to use RailsPanel Chrome extension --- Gemfile | 4 ++++ Gemfile.lock | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/Gemfile b/Gemfile index ac935b7..3d97dcf 100644 --- a/Gemfile +++ b/Gemfile @@ -38,3 +38,7 @@ gem 'sorcery' gem 'will_paginate', '~> 3.0' gem 'activerecord-postgresql-adapter' gem 'pg' + +group :development do + gem 'meta_request', '0.2.1' +end diff --git a/Gemfile.lock b/Gemfile.lock index 2168b8f..644fae3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -80,6 +80,9 @@ GEM i18n (>= 0.4.0) mime-types (~> 1.16) treetop (~> 1.4.8) + meta_request (0.2.1) + rack-contrib + rails mime-types (1.21) multi_json (1.6.1) multipart-post (1.1.5) @@ -96,6 +99,8 @@ GEM rack (1.4.5) rack-cache (1.2) rack (>= 0.4) + rack-contrib (1.1.0) + rack (>= 0.9.1) rack-ssl (1.3.3) rack rack-test (0.6.2) @@ -155,6 +160,7 @@ DEPENDENCIES haml-rails htmlentities jquery-rails + meta_request (= 0.2.1) pg rails (= 3.2.12) sass-rails (~> 3.2.3) From da5e5adbafa2876972f99fcdf0e757f0480bcd74 Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Fri, 22 Feb 2013 12:03:26 +0000 Subject: [PATCH 11/32] Remove username from users table --- db/migrate/20130222120002_remove_user_username.rb | 9 +++++++++ db/schema.rb | 3 +-- 2 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20130222120002_remove_user_username.rb diff --git a/db/migrate/20130222120002_remove_user_username.rb b/db/migrate/20130222120002_remove_user_username.rb new file mode 100644 index 0000000..4bf89bd --- /dev/null +++ b/db/migrate/20130222120002_remove_user_username.rb @@ -0,0 +1,9 @@ +class RemoveUserUsername < ActiveRecord::Migration + def up + remove_column :users, :username + end + + def down + add_column :users, :username, :string, :null => false + end +end diff --git a/db/schema.rb b/db/schema.rb index 8cc6775..ffee706 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 => 20130222112030) do +ActiveRecord::Schema.define(:version => 20130222120002) do create_table "feeds", :force => true do |t| t.string "title" @@ -40,7 +40,6 @@ ActiveRecord::Schema.define(:version => 20130222112030) do end create_table "users", :force => true do |t| - t.string "username", :null => false t.string "email" t.string "crypted_password" t.string "salt" From 48973b59fd8ff63b59e454d0d71ce7011fb4e361 Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Fri, 22 Feb 2013 12:35:43 +0000 Subject: [PATCH 12/32] Add guid column to posts; remove guid column from feeds --- ...130222123224_add_guid_to_posts_remove_guid_from_feeds.rb | 6 ++++++ db/schema.rb | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20130222123224_add_guid_to_posts_remove_guid_from_feeds.rb diff --git a/db/migrate/20130222123224_add_guid_to_posts_remove_guid_from_feeds.rb b/db/migrate/20130222123224_add_guid_to_posts_remove_guid_from_feeds.rb new file mode 100644 index 0000000..d2a4d35 --- /dev/null +++ b/db/migrate/20130222123224_add_guid_to_posts_remove_guid_from_feeds.rb @@ -0,0 +1,6 @@ +class AddGuidToPostsRemoveGuidFromFeeds < ActiveRecord::Migration + def change + remove_column :feeds, :guid + add_column :posts, :guid, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index ffee706..e2dfefd 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,14 +11,13 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20130222120002) do +ActiveRecord::Schema.define(:version => 20130222123224) do create_table "feeds", :force => true do |t| t.string "title" t.string "feed_url" t.string "url" t.string "description" - t.string "guid" t.string "generator" t.time "last_fetched" t.datetime "created_at", :null => false @@ -37,6 +36,7 @@ ActiveRecord::Schema.define(:version => 20130222120002) do t.integer "feed_id" t.datetime "created_at", :null => false t.datetime "updated_at", :null => false + t.string "guid" end create_table "users", :force => true do |t| From 2dc6636d600c42922ef78d89d1b81d2824d99700 Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Fri, 22 Feb 2013 13:01:33 +0000 Subject: [PATCH 13/32] Change feeds.last_fetched and posts.published to datetime --- ...222123833_feeds_change_last_fetched_to_datetime.rb | 11 +++++++++++ ...0130222125833_post_published_change_to_datetime.rb | 11 +++++++++++ db/schema.rb | 6 +++--- 3 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 db/migrate/20130222123833_feeds_change_last_fetched_to_datetime.rb create mode 100644 db/migrate/20130222125833_post_published_change_to_datetime.rb diff --git a/db/migrate/20130222123833_feeds_change_last_fetched_to_datetime.rb b/db/migrate/20130222123833_feeds_change_last_fetched_to_datetime.rb new file mode 100644 index 0000000..22aabf0 --- /dev/null +++ b/db/migrate/20130222123833_feeds_change_last_fetched_to_datetime.rb @@ -0,0 +1,11 @@ +class FeedsChangeLastFetchedToDatetime < ActiveRecord::Migration + def up + remove_column :feeds, :last_fetched + add_column :feeds, :last_fetched, :datetime + end + + def down + remove_column :feeds, :last_fetched + add_column :feeds, :last_fetched, :time + end +end diff --git a/db/migrate/20130222125833_post_published_change_to_datetime.rb b/db/migrate/20130222125833_post_published_change_to_datetime.rb new file mode 100644 index 0000000..3e27fbf --- /dev/null +++ b/db/migrate/20130222125833_post_published_change_to_datetime.rb @@ -0,0 +1,11 @@ +class PostPublishedChangeToDatetime < ActiveRecord::Migration + def up + remove_column :posts, :published + add_column :posts, :published, :datetime + end + + def down + remove_column :posts, :published + add_column :posts, :published, :time + end +end diff --git a/db/schema.rb b/db/schema.rb index e2dfefd..1b9c52f 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 => 20130222123224) do +ActiveRecord::Schema.define(:version => 20130222125833) do create_table "feeds", :force => true do |t| t.string "title" @@ -19,9 +19,9 @@ ActiveRecord::Schema.define(:version => 20130222123224) do t.string "url" t.string "description" t.string "generator" - t.time "last_fetched" t.datetime "created_at", :null => false t.datetime "updated_at", :null => false + t.datetime "last_fetched" end create_table "posts", :force => true do |t| @@ -30,13 +30,13 @@ ActiveRecord::Schema.define(:version => 20130222123224) do t.string "author" t.text "summary" t.text "content" - t.time "published" t.decimal "lat" t.decimal "lon" t.integer "feed_id" t.datetime "created_at", :null => false t.datetime "updated_at", :null => false t.string "guid" + t.datetime "published" end create_table "users", :force => true do |t| From 18403cbc29e06968f1cdf8c652ac559377a8456d Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Fri, 22 Feb 2013 13:12:34 +0000 Subject: [PATCH 14/32] Rename get and get_all methods to fetch and fetch_all --- app/controllers/feeds_controller.rb | 4 ++-- app/models/feed.rb | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/controllers/feeds_controller.rb b/app/controllers/feeds_controller.rb index 77573f6..54d2497 100644 --- a/app/controllers/feeds_controller.rb +++ b/app/controllers/feeds_controller.rb @@ -87,12 +87,12 @@ class FeedsController < ApplicationController def fetch @feed = Feed.find(params[:id]) - @feed.get + @feed.fetch redirect_to :back, notice: 'Feed fetched OK' end def fetch_all - Feed.get_all + Feed.fetch_all redirect_to :back, notice: 'All feeds fetched OK' end end diff --git a/app/models/feed.rb b/app/models/feed.rb index 9271d1f..ab6ee2f 100644 --- a/app/models/feed.rb +++ b/app/models/feed.rb @@ -5,15 +5,19 @@ class Feed < ActiveRecord::Base validates_format_of :feed_url, :with => URI::regexp(%w(http https)), :message => "must be a valid URL" after_create :get + after_create :fetch # Fetch and parse feed contents from web def self.get_all Feed.all.each { |f| f.get } + def self.fetch_all + Feed.all.each { |f| f.fetch } end def get puts "Fetching feed: #{@url}" + def fetch Feedzirra::Feed.add_common_feed_entry_element('georss:point', :as => :point) Feedzirra::Feed.add_common_feed_entry_element('geo:lat', :as => :geo_lat) Feedzirra::Feed.add_common_feed_entry_element('geo:long', :as => :geo_long) From 5355646760bd4522a6f47c86ef34de51012cb878 Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Fri, 22 Feb 2013 13:13:37 +0000 Subject: [PATCH 15/32] Use ActiveRecord style ordering --- app/controllers/feeds_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/feeds_controller.rb b/app/controllers/feeds_controller.rb index 54d2497..2f6720d 100644 --- a/app/controllers/feeds_controller.rb +++ b/app/controllers/feeds_controller.rb @@ -17,8 +17,8 @@ class FeedsController < ApplicationController # GET /feeds/1.json def show @feed = Feed.find(params[:id]) - @posts = @feed.posts.sort(:published.desc).paginate(:page => params[:page], :per_page => 20) - + @posts = @feed.posts.order("published desc").paginate(:page => params[:page], :per_page => 20) + respond_to do |format| format.html # show.html.erb format.json { render json: @feed } From e3950bb614a9fb248e5b010a09470e24e60b86a2 Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Fri, 22 Feb 2013 13:13:54 +0000 Subject: [PATCH 16/32] Use new lat and lon attributes --- app/views/feeds/show.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/feeds/show.html.haml b/app/views/feeds/show.html.haml index fe65166..4863bc5 100644 --- a/app/views/feeds/show.html.haml +++ b/app/views/feeds/show.html.haml @@ -28,7 +28,7 @@ - @posts.each do |p| %tr %td= link_to p.title, p.url - %td= link_to "Map", "https://maps.google.co.uk/maps?q=%s,%s&hl=en&z=18" % [ p.loc['lat'], p.loc['lng'] ], :target => "_blank" + %td= link_to "Map", "https://maps.google.co.uk/maps?q=%s,%s&hl=en&z=18" % [ p.lat, p.lon ], :target => "_blank" %td - unless p.published.nil? = p.published.strftime("%d %b %Y %H:%M") From 2b813b835b337cee13ea3bbfa20850c9e78b2e8a Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Fri, 22 Feb 2013 13:51:31 +0000 Subject: [PATCH 17/32] Make attributes accessible --- app/models/feed.rb | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/app/models/feed.rb b/app/models/feed.rb index ab6ee2f..fe933d2 100644 --- a/app/models/feed.rb +++ b/app/models/feed.rb @@ -1,5 +1,6 @@ class Feed < ActiveRecord::Base has_many :posts, :dependent => :destroy + attr_accessible :title, :url, :description, :generator, :last_fetched, :feed_url validates :title, :presence => true validates_format_of :feed_url, :with => URI::regexp(%w(http https)), :message => "must be a valid URL" @@ -36,9 +37,9 @@ class Feed < ActiveRecord::Base feed.entries.each do |e| if e.geo_lat && e.geo_long - latlng = [e.geo_lat, e.geo_long] + latlon = [e.geo_lat, e.geo_long] elsif e.point - latlng = e.point.split(' ') + latlon = e.point.split(' ') else next end @@ -51,20 +52,15 @@ class Feed < ActiveRecord::Base :content => e.content, :published => e.published, :guid => e.id, - :loc => { - :lng => latlng[1].to_f, - :lat => latlng[0].to_f - } + :lon => latlon[1].to_f, + :lat => latlon[0].to_f } - if Post.where(:url => e.url).size == 0 - self.posts << Post.create(attrs) - else - Post.set({:url => e.url}, attrs) - end - + # Create a new post or update an existing one + post = Post.find_or_initialize_by_url(e.url) + post.feed = self + post.assign_attributes(attrs) + post.save end - end - end From 44e5e17a17255c073c3ddac4c76b60ca0850f7a7 Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Fri, 22 Feb 2013 13:52:56 +0000 Subject: [PATCH 18/32] Use ActiveRecord style --- app/models/feed.rb | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/app/models/feed.rb b/app/models/feed.rb index fe933d2..b826fc0 100644 --- a/app/models/feed.rb +++ b/app/models/feed.rb @@ -2,36 +2,30 @@ class Feed < ActiveRecord::Base has_many :posts, :dependent => :destroy attr_accessible :title, :url, :description, :generator, :last_fetched, :feed_url - validates :title, :presence => true validates_format_of :feed_url, :with => URI::regexp(%w(http https)), :message => "must be a valid URL" - after_create :get after_create :fetch - # Fetch and parse feed contents from web - - def self.get_all - Feed.all.each { |f| f.get } def self.fetch_all Feed.all.each { |f| f.fetch } end - def get - puts "Fetching feed: #{@url}" + # Fetch and parse feed contents from web def fetch + puts "Fetching feed: #{self.feed_url}" Feedzirra::Feed.add_common_feed_entry_element('georss:point', :as => :point) Feedzirra::Feed.add_common_feed_entry_element('geo:lat', :as => :geo_lat) Feedzirra::Feed.add_common_feed_entry_element('geo:long', :as => :geo_long) Feedzirra::Feed.add_common_feed_element('generator', :as => :generator) - feed = Feedzirra::Feed.fetch_and_parse(@feed_url) + feed = Feedzirra::Feed.fetch_and_parse(self.feed_url) - self.set( + self.update_attributes( :title => feed.title, :url => feed.url, :description => feed.description, :generator => feed.generator, - :last_fetched => Time.now + :last_fetched => DateTime.now ) feed.entries.each do |e| @@ -42,8 +36,8 @@ class Feed < ActiveRecord::Base latlon = e.point.split(' ') else next - end - + end + attrs = { :title => e.title, :url => e.url, From cc5a1c0103339edd7b64a70a70ca6cc4bc610410 Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Fri, 22 Feb 2013 15:03:31 +0000 Subject: [PATCH 19/32] Use new lat/lon attributes; add table header --- app/views/posts/near.html.haml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/app/views/posts/near.html.haml b/app/views/posts/near.html.haml index 3a14668..f967592 100644 --- a/app/views/posts/near.html.haml +++ b/app/views/posts/near.html.haml @@ -1,11 +1,20 @@ %h1 Posts#near %table + %thead + %tr + %th + %th Latitude + %th Longitude + %th Distance (metres) + %th Published + %tbody - @posts.each do |p| %tr %td= link_to p.title, p.url - %td= p.loc['lat'] - %td= p.loc['lng'] + %td= p.lat + %td= p.lon + %td= p.distance.to_i %td - unless p.published.nil? = p.published.strftime("%d %b %Y %H:%M") From 734013cd1a11be4e6f4fbf344e1fb94d93cdfb6f Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Fri, 22 Feb 2013 15:05:03 +0000 Subject: [PATCH 20/32] Convert from MongoDB geolocation finder to raw SQL query --- app/models/post.rb | 52 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/app/models/post.rb b/app/models/post.rb index 73fe0d4..dd62fc6 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -1,13 +1,51 @@ class Post < ActiveRecord::Base belongs_to :feed - EARTH_RADIUS_M = 6378000 + EARTH_RADIUS_METRES = 6378000 - def self.near(lat, lng, radius_m) - all( - :loc => { - '$nearSphere' => [ lng, lat ], - '$maxDistance' => radius_m / EARTH_RADIUS_M - }) + def self.near(lat, lon, radius_metres) + # Santize inputs. Is this necessary? + lat = lat.to_f + lon = lon.to_f + radius_metres = radius_metres.to_i + + # Calculate distance using the Haversine formula + self.find_by_sql(<<-ENDQUERY + SELECT + p.id, + p.title, + p.summary, + p.url, + p.lat, + p.lon, + p.published, + f.title as feed_title, + ( #{EARTH_RADIUS_METRES} + * acos( cos( radians('#{lat}') ) + * cos( radians( p.lat ) ) + * cos( radians( p.lon ) + - radians('#{lon}') ) + + sin( radians('#{lat}') ) + * sin( radians( p.lat ) ) ) ) + As distance + + FROM posts p + INNER JOIN feeds f + ON p.feed_id = f.id + + WHERE + ( #{EARTH_RADIUS_METRES} + * acos( cos( radians('#{lat}') ) + * cos( radians( p.lat ) ) + * cos( radians( p.lon ) + - radians('#{lon}') ) + + sin( radians('#{lat}') ) + * sin( radians( p.lat ) ) ) ) + < #{radius_metres} + + ORDER BY distance + + ENDQUERY + ) end end From 75259fefb90e15aac80ac8f09f1d37693526597d Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Fri, 22 Feb 2013 15:05:29 +0000 Subject: [PATCH 21/32] Use new lat/lon and feed title attributes --- app/helpers/posts_helper.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/helpers/posts_helper.rb b/app/helpers/posts_helper.rb index 8325f46..3e77a72 100644 --- a/app/helpers/posts_helper.rb +++ b/app/helpers/posts_helper.rb @@ -6,15 +6,15 @@ module PostsHelper :imageURL => "%s%s/assets/layar-icons/tal-logo-100.png" % [ request.protocol, request.env['HTTP_HOST'] ], :anchor => { :geolocation => { - :lat => post.loc['lat'], - :lon => post.loc['lng'], + :lat => post.lat, + :lon => post.lon, :alt => 0 } }, :text => { :title => decode_entities(post.title), :description => clean_description(post.summary), - :footnote => "From #{post.feed.title}" + :footnote => "From #{post.feed_title}" }, :actions => [ { From e7da0f5ba30c9bdb846ffc986d372e322593803c Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Fri, 22 Feb 2013 21:20:24 +0000 Subject: [PATCH 22/32] Make radius range inclusive --- app/models/post.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/post.rb b/app/models/post.rb index dd62fc6..489a990 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -41,7 +41,7 @@ class Post < ActiveRecord::Base - radians('#{lon}') ) + sin( radians('#{lat}') ) * sin( radians( p.lat ) ) ) ) - < #{radius_metres} + <= #{radius_metres} ORDER BY distance From e2ff740fd7c26a869e6361a5253c692ddca2a1d7 Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Thu, 28 Feb 2013 15:06:03 +0000 Subject: [PATCH 23/32] Add better_errors and binding_of_caller gems for debugging --- Gemfile | 4 +++- Gemfile.lock | 11 ++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index 3d97dcf..aa2c8c9 100644 --- a/Gemfile +++ b/Gemfile @@ -40,5 +40,7 @@ gem 'activerecord-postgresql-adapter' gem 'pg' group :development do - gem 'meta_request', '0.2.1' + gem 'meta_request' + gem 'better_errors' + gem 'binding_of_caller' end diff --git a/Gemfile.lock b/Gemfile.lock index 644fae3..269c60d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -32,7 +32,13 @@ GEM multi_json (~> 1.0) arel (3.0.2) bcrypt-ruby (3.0.1) + better_errors (0.6.0) + coderay (>= 1.0.0) + erubis (>= 2.6.6) + binding_of_caller (0.7.1) + debug_inspector (>= 0.0.1) builder (3.0.4) + coderay (1.0.9) coffee-rails (3.2.2) coffee-script (>= 2.2.0) railties (~> 3.2.0) @@ -41,6 +47,7 @@ GEM execjs coffee-script-source (1.4.0) curb (0.7.18) + debug_inspector (0.0.2) erubis (2.7.0) execjs (1.4.0) multi_json (~> 1.0) @@ -155,12 +162,14 @@ PLATFORMS DEPENDENCIES activerecord-postgresql-adapter + better_errors + binding_of_caller coffee-rails (~> 3.2.1) feedzirra haml-rails htmlentities jquery-rails - meta_request (= 0.2.1) + meta_request pg rails (= 3.2.12) sass-rails (~> 3.2.3) From 206303f9e685e0d1527f1738a9cacbce434222e9 Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Thu, 28 Feb 2013 15:14:06 +0000 Subject: [PATCH 24/32] Add Layer model/scaffold with a join table to habtm feeds --- app/assets/javascripts/layers.js.coffee | 3 + app/assets/stylesheets/layers.css.scss | 3 + app/controllers/layers_controller.rb | 83 ++++++++++++++++++++++ app/helpers/layers_helper.rb | 2 + app/models/feed.rb | 1 + app/models/layer.rb | 4 ++ app/views/layers/_form.html.haml | 13 ++++ app/views/layers/edit.html.haml | 7 ++ app/views/layers/index.html.haml | 19 +++++ app/views/layers/new.html.haml | 5 ++ app/views/layers/show.html.haml | 9 +++ config/routes.rb | 3 + db/migrate/20130228150425_create_layers.rb | 15 ++++ db/schema.rb | 15 +++- test/fixtures/layers.yml | 7 ++ test/functional/layers_controller_test.rb | 49 +++++++++++++ test/unit/helpers/layers_helper_test.rb | 4 ++ test/unit/layer_test.rb | 7 ++ 18 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 app/assets/javascripts/layers.js.coffee create mode 100644 app/assets/stylesheets/layers.css.scss create mode 100644 app/controllers/layers_controller.rb create mode 100644 app/helpers/layers_helper.rb create mode 100644 app/models/layer.rb create mode 100644 app/views/layers/_form.html.haml create mode 100644 app/views/layers/edit.html.haml create mode 100644 app/views/layers/index.html.haml create mode 100644 app/views/layers/new.html.haml create mode 100644 app/views/layers/show.html.haml create mode 100644 db/migrate/20130228150425_create_layers.rb create mode 100644 test/fixtures/layers.yml create mode 100644 test/functional/layers_controller_test.rb create mode 100644 test/unit/helpers/layers_helper_test.rb create mode 100644 test/unit/layer_test.rb diff --git a/app/assets/javascripts/layers.js.coffee b/app/assets/javascripts/layers.js.coffee new file mode 100644 index 0000000..7615679 --- /dev/null +++ b/app/assets/javascripts/layers.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/assets/stylesheets/layers.css.scss b/app/assets/stylesheets/layers.css.scss new file mode 100644 index 0000000..3a0518b --- /dev/null +++ b/app/assets/stylesheets/layers.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Layers controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/layers_controller.rb b/app/controllers/layers_controller.rb new file mode 100644 index 0000000..430a7ae --- /dev/null +++ b/app/controllers/layers_controller.rb @@ -0,0 +1,83 @@ +class LayersController < ApplicationController + # GET /layers + # GET /layers.json + def index + @layers = Layer.all + + respond_to do |format| + format.html # index.html.erb + format.json { render json: @layers } + end + end + + # GET /layers/1 + # GET /layers/1.json + def show + @layer = Layer.find(params[:id]) + + respond_to do |format| + format.html # show.html.erb + format.json { render json: @layer } + end + end + + # GET /layers/new + # GET /layers/new.json + def new + @layer = Layer.new + + respond_to do |format| + format.html # new.html.erb + format.json { render json: @layer } + end + end + + # GET /layers/1/edit + def edit + @layer = Layer.find(params[:id]) + end + + # POST /layers + # POST /layers.json + def create + @layer = Layer.new(params[:layer]) + + respond_to do |format| + if @layer.save + format.html { redirect_to @layer, notice: 'Layer was successfully created.' } + format.json { render json: @layer, status: :created, location: @layer } + else + format.html { render action: "new" } + format.json { render json: @layer.errors, status: :unprocessable_entity } + end + end + end + + # PUT /layers/1 + # PUT /layers/1.json + def update + @layer = Layer.find(params[:id]) + + respond_to do |format| + if @layer.update_attributes(params[:layer]) + format.html { redirect_to @layer, notice: 'Layer was successfully updated.' } + format.json { head :no_content } + else + format.html { render action: "edit" } + format.json { render json: @layer.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /layers/1 + # DELETE /layers/1.json + def destroy + @layer = Layer.find(params[:id]) + @layer.destroy + + respond_to do |format| + format.html { redirect_to layers_url } + format.json { head :no_content } + end + end +end diff --git a/app/helpers/layers_helper.rb b/app/helpers/layers_helper.rb new file mode 100644 index 0000000..b8dbc16 --- /dev/null +++ b/app/helpers/layers_helper.rb @@ -0,0 +1,2 @@ +module LayersHelper +end diff --git a/app/models/feed.rb b/app/models/feed.rb index b826fc0..755bb04 100644 --- a/app/models/feed.rb +++ b/app/models/feed.rb @@ -1,5 +1,6 @@ class Feed < ActiveRecord::Base has_many :posts, :dependent => :destroy + has_and_belongs_to_many :layers attr_accessible :title, :url, :description, :generator, :last_fetched, :feed_url validates_format_of :feed_url, :with => URI::regexp(%w(http https)), :message => "must be a valid URL" diff --git a/app/models/layer.rb b/app/models/layer.rb new file mode 100644 index 0000000..86d2ff0 --- /dev/null +++ b/app/models/layer.rb @@ -0,0 +1,4 @@ +class Layer < ActiveRecord::Base + attr_accessible :name + has_and_belongs_to_many :feeds +end diff --git a/app/views/layers/_form.html.haml b/app/views/layers/_form.html.haml new file mode 100644 index 0000000..27bc898 --- /dev/null +++ b/app/views/layers/_form.html.haml @@ -0,0 +1,13 @@ += form_for @layer do |f| + - if @layer.errors.any? + #error_explanation + %h2= "#{pluralize(@layer.errors.count, "error")} prohibited this layer from being saved:" + %ul + - @layer.errors.full_messages.each do |msg| + %li= msg + + .field + = f.label :name + = f.text_field :name + .actions + = f.submit 'Save' diff --git a/app/views/layers/edit.html.haml b/app/views/layers/edit.html.haml new file mode 100644 index 0000000..9c013b7 --- /dev/null +++ b/app/views/layers/edit.html.haml @@ -0,0 +1,7 @@ +%h1 Editing layer + += render 'form' + += link_to 'Show', @layer +\| += link_to 'Back', layers_path diff --git a/app/views/layers/index.html.haml b/app/views/layers/index.html.haml new file mode 100644 index 0000000..29618df --- /dev/null +++ b/app/views/layers/index.html.haml @@ -0,0 +1,19 @@ +%h1 Listing layers + +%table + %tr + %th Name + %th + %th + %th + + - @layers.each do |layer| + %tr + %td= layer.name + %td= link_to 'Show', layer + %td= link_to 'Edit', edit_layer_path(layer) + %td= link_to 'Destroy', layer, :method => :delete, :data => { :confirm => 'Are you sure?' } + +%br + += link_to 'New Layer', new_layer_path diff --git a/app/views/layers/new.html.haml b/app/views/layers/new.html.haml new file mode 100644 index 0000000..73ddc96 --- /dev/null +++ b/app/views/layers/new.html.haml @@ -0,0 +1,5 @@ +%h1 New layer + += render 'form' + += link_to 'Back', layers_path diff --git a/app/views/layers/show.html.haml b/app/views/layers/show.html.haml new file mode 100644 index 0000000..3bad3dc --- /dev/null +++ b/app/views/layers/show.html.haml @@ -0,0 +1,9 @@ +%p#notice= notice + +%p + %b Name: + = @layer.name + += link_to 'Edit', edit_layer_path(@layer) +\| += link_to 'Back', layers_path diff --git a/config/routes.rb b/config/routes.rb index 6cbea69..288e017 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,7 @@ Apollo::Application.routes.draw do + resources :layers + + get "logout" => "sessions#destroy", :as => "logout" get "login" => "sessions#new", :as => "login" diff --git a/db/migrate/20130228150425_create_layers.rb b/db/migrate/20130228150425_create_layers.rb new file mode 100644 index 0000000..4ad96d7 --- /dev/null +++ b/db/migrate/20130228150425_create_layers.rb @@ -0,0 +1,15 @@ +class CreateLayers < ActiveRecord::Migration + def change + create_table :layers do |t| + t.string :name + t.timestamps + end + + create_table :feeds_layers, :id => false do |t| + t.integer :feed_id + t.integer :layer_id + end + + add_index :feeds_layers, [ :feed_id, :layer_id ] + end +end diff --git a/db/schema.rb b/db/schema.rb index 1b9c52f..f6c1318 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 => 20130222125833) do +ActiveRecord::Schema.define(:version => 20130228150425) do create_table "feeds", :force => true do |t| t.string "title" @@ -24,6 +24,19 @@ ActiveRecord::Schema.define(:version => 20130222125833) do t.datetime "last_fetched" end + create_table "feeds_layers", :id => false, :force => true do |t| + t.integer "feed_id" + t.integer "layer_id" + end + + add_index "feeds_layers", ["feed_id", "layer_id"], :name => "index_feeds_layers_on_feed_id_and_layer_id" + + create_table "layers", :force => true do |t| + t.string "name" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + create_table "posts", :force => true do |t| t.string "title" t.string "url" diff --git a/test/fixtures/layers.yml b/test/fixtures/layers.yml new file mode 100644 index 0000000..0227c60 --- /dev/null +++ b/test/fixtures/layers.yml @@ -0,0 +1,7 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html + +one: + name: MyString + +two: + name: MyString diff --git a/test/functional/layers_controller_test.rb b/test/functional/layers_controller_test.rb new file mode 100644 index 0000000..d6dc765 --- /dev/null +++ b/test/functional/layers_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class LayersControllerTest < ActionController::TestCase + setup do + @layer = layers(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:layers) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create layer" do + assert_difference('Layer.count') do + post :create, layer: { name: @layer.name } + end + + assert_redirected_to layer_path(assigns(:layer)) + end + + test "should show layer" do + get :show, id: @layer + assert_response :success + end + + test "should get edit" do + get :edit, id: @layer + assert_response :success + end + + test "should update layer" do + put :update, id: @layer, layer: { name: @layer.name } + assert_redirected_to layer_path(assigns(:layer)) + end + + test "should destroy layer" do + assert_difference('Layer.count', -1) do + delete :destroy, id: @layer + end + + assert_redirected_to layers_path + end +end diff --git a/test/unit/helpers/layers_helper_test.rb b/test/unit/helpers/layers_helper_test.rb new file mode 100644 index 0000000..ad81667 --- /dev/null +++ b/test/unit/helpers/layers_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class LayersHelperTest < ActionView::TestCase +end diff --git a/test/unit/layer_test.rb b/test/unit/layer_test.rb new file mode 100644 index 0000000..29c3aa3 --- /dev/null +++ b/test/unit/layer_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class LayerTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end From 96475c860d298ab9acbea4cac984c34ff31c96cb Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Tue, 19 Mar 2013 14:57:53 +0000 Subject: [PATCH 25/32] Only query for posts on the specified layer --- app/models/post.rb | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/app/models/post.rb b/app/models/post.rb index 489a990..598edf4 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -3,11 +3,12 @@ class Post < ActiveRecord::Base EARTH_RADIUS_METRES = 6378000 - def self.near(lat, lon, radius_metres) + def self.near(lat, lon, radius_metres, layer_id) # Santize inputs. Is this necessary? lat = lat.to_f lon = lon.to_f radius_metres = radius_metres.to_i + layer_id = layer_id.to_i # Calculate distance using the Haversine formula self.find_by_sql(<<-ENDQUERY @@ -34,13 +35,31 @@ class Post < ActiveRecord::Base ON p.feed_id = f.id WHERE - ( #{EARTH_RADIUS_METRES} - * acos( cos( radians('#{lat}') ) - * cos( radians( p.lat ) ) - * cos( radians( p.lon ) - - radians('#{lon}') ) - + sin( radians('#{lat}') ) - * sin( radians( p.lat ) ) ) ) + p.id IN + ( -- Subquery returns a list of post_ids for posts on this layer + SELECT p.id + + FROM feeds_layers fl + + INNER JOIN feeds f + ON fl.feed_id = f.id + + INNER JOIN posts p + ON p.feed_id = f.id + + WHERE fl.layer_id = #{layer_id} + ) + + AND + ( + #{EARTH_RADIUS_METRES} + * acos( cos( radians('#{lat}') ) + * cos( radians( p.lat ) ) + * cos( radians( p.lon ) + - radians('#{lon}') ) + + sin( radians('#{lat}') ) + * sin( radians( p.lat ) ) ) + ) <= #{radius_metres} ORDER BY distance From dab7c7ae44f5d5030b1428e2d77f94fbdcf36756 Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Tue, 19 Mar 2013 15:00:28 +0000 Subject: [PATCH 26/32] Add layer_id param --- app/controllers/posts_controller.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index c0c12fb..d53db30 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -2,13 +2,13 @@ class PostsController < ApplicationController include PostsHelper def near - @posts = Post.near(params[:lat].to_f, params[:lon].to_f, params[:radius].to_f) + @posts = Post.near(params[:lat].to_f, params[:lon].to_f, params[:radius].to_f, params[:layer_id]) - ErrorLog.create( - :ts => Time.now, - :params => params, - :pois_returned => @posts.size - ) +# ErrorLog.create( +# :ts => Time.now, +# :params => params, +# :pois_returned => @posts.size +# ) layar_response = { :layer => 'hyparlocal', From 0261bc131805933e3f1bd1015060a42f583347d6 Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Tue, 19 Mar 2013 15:01:15 +0000 Subject: [PATCH 27/32] Create new feeds in the context of a specified layer --- app/controllers/feeds_controller.rb | 20 ++++++++++++++++++-- app/models/feed.rb | 1 + app/views/feeds/_form.html.haml | 1 + 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/app/controllers/feeds_controller.rb b/app/controllers/feeds_controller.rb index 2f6720d..28cf6fc 100644 --- a/app/controllers/feeds_controller.rb +++ b/app/controllers/feeds_controller.rb @@ -44,11 +44,27 @@ class FeedsController < ApplicationController # POST /feeds # POST /feeds.json def create - @feed = Feed.new(params[:feed]) + + + Rails.logger.debug "Feed URL: %s" % params['feed']['feed_url'] + + if Feed.where(:feed_url => params['feed']['feed_url']).size == 1 # ensure this test returns the values we expect + Rails.logger.debug "Adding existing feed to a new layer" + @feed = Feed.where(:feed_url => params['feed']['feed_url']).first + @layer = Layer.find(params['feed']['new_layer_id']) # assumes that the specified layer exists + # Attach the existing feed to the specified layer (making sure we only add each one once) + @feed.layers << @layer unless @feed.layers.include?(@layer) + else + # Create a new feed + Rails.logger.debug "Creating a new feed" + @feed = Feed.new(params[:feed]) + @layer = Layer.find(params['feed']['new_layer_id']) # assumes that the specified layer exists + @feed.layers << @layer unless @feed.layers.include?(@layer) + end respond_to do |format| if @feed.save - format.html { redirect_to '/', notice: 'Feed added OK' } + format.html { redirect_to @layer, notice: 'Feed added OK' } format.json { render json: @feed, status: :created, location: @feed } else format.html { render action: "new" } diff --git a/app/models/feed.rb b/app/models/feed.rb index 755bb04..e07fc45 100644 --- a/app/models/feed.rb +++ b/app/models/feed.rb @@ -2,6 +2,7 @@ class Feed < ActiveRecord::Base has_many :posts, :dependent => :destroy has_and_belongs_to_many :layers attr_accessible :title, :url, :description, :generator, :last_fetched, :feed_url + attr_accessor :new_layer_id # non model attribute used when creating new feeds from within a layer validates_format_of :feed_url, :with => URI::regexp(%w(http https)), :message => "must be a valid URL" diff --git a/app/views/feeds/_form.html.haml b/app/views/feeds/_form.html.haml index 70a4b73..60e59dc 100644 --- a/app/views/feeds/_form.html.haml +++ b/app/views/feeds/_form.html.haml @@ -15,6 +15,7 @@ .field = f.label "URL" = f.text_field :feed_url, :size => 120 + = f.hidden_field :new_layer_id, :value => @feed.new_layer_id = f.submit 'Save', :id => 'submit' -# .field From 34dee39c849649e94243b7bd73f86406c8a7f27a Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Tue, 19 Mar 2013 15:02:03 +0000 Subject: [PATCH 28/32] Set root URL to layers index --- config/routes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/routes.rb b/config/routes.rb index 288e017..cdc93fe 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -68,7 +68,7 @@ Apollo::Application.routes.draw do # You can have the root of your site routed with "root" # just remember to delete public/index.html. - root :to => 'feeds#index' + root :to => 'layers#index' # See how all your routes lay out with "rake routes" From 2e42b6b07698e7afd1b0d7221b3b8ac767f70914 Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Tue, 19 Mar 2013 15:04:18 +0000 Subject: [PATCH 29/32] Improve layout --- app/views/layers/index.html.haml | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/app/views/layers/index.html.haml b/app/views/layers/index.html.haml index 29618df..1b773c5 100644 --- a/app/views/layers/index.html.haml +++ b/app/views/layers/index.html.haml @@ -1,19 +1,10 @@ -%h1 Listing layers +%h1 Layers -%table - %tr - %th Name - %th - %th - %th += link_to 'New Layer', new_layer_path, :class => 'button' +%table - @layers.each do |layer| %tr - %td= layer.name - %td= link_to 'Show', layer + %td= link_to layer.name, layer %td= link_to 'Edit', edit_layer_path(layer) - %td= link_to 'Destroy', layer, :method => :delete, :data => { :confirm => 'Are you sure?' } - -%br - -= link_to 'New Layer', new_layer_path + %td= link_to 'Delete', layer, :method => :delete, :data => { :confirm => 'Are you sure?' } From c2b96bafa55ab34b01a708f43f6a896a21f18a41 Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Tue, 19 Mar 2013 15:05:35 +0000 Subject: [PATCH 30/32] Show feeds for this layer; show API URL --- app/views/layers/show.html.haml | 48 ++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/app/views/layers/show.html.haml b/app/views/layers/show.html.haml index 3bad3dc..546aaeb 100644 --- a/app/views/layers/show.html.haml +++ b/app/views/layers/show.html.haml @@ -1,8 +1,50 @@ -%p#notice= notice +%h1 + Layer: + = @layer.name %p - %b Name: - = @layer.name + API URL: + = "#{request.protocol}#{request.host_with_port}/posts/near.json?layer_id=#{@layer.id}" + + +%h2 Feeds + +#new_feed + = render 'feeds/form' + +%p= link_to "Fetch all", :fetch_all, :class => "button" + +%table + %tr + %th + %th Posts + %th Fetched + %th + %th + %th + + - @layer.feeds.each do |f| + %tr + %td + .feed_title + = link_to f.title, f + %td.right= f.posts.count + %td + - if f.last_fetched.nil? + never + - else + = (time_ago_in_words(f.last_fetched) + " ago").gsub(/ +/, " ").html_safe + %td= link_to "Fetch", fetch_feed_url(f), :class => "button" + %td= link_to 'Edit', edit_feed_path(f), :class => "button" + %td= link_to 'Delete', f, :confirm => "Delete #{f.title} and all its posts?", :method => :delete, :class => "button" + + %tr + %td + %td.right [number of posts in this layer] + %td + %td + %td + %td = link_to 'Edit', edit_layer_path(@layer) \| From 8046b9b25b87c3ffcf944d49e513f3a92dd53d31 Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Tue, 19 Mar 2013 15:05:58 +0000 Subject: [PATCH 31/32] Create new feeds in the context of this layer --- app/controllers/layers_controller.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/controllers/layers_controller.rb b/app/controllers/layers_controller.rb index 430a7ae..b69537d 100644 --- a/app/controllers/layers_controller.rb +++ b/app/controllers/layers_controller.rb @@ -14,6 +14,8 @@ class LayersController < ApplicationController # GET /layers/1.json def show @layer = Layer.find(params[:id]) + @feed = Feed.new + @feed.new_layer_id = @layer.id respond_to do |format| format.html # show.html.erb From 3b12db06b110327bf294a2d4a1c2962ff42afc34 Mon Sep 17 00:00:00 2001 From: Adrian Short Date: Tue, 19 Mar 2013 15:29:12 +0000 Subject: [PATCH 32/32] Tidy up blank lines --- config/routes.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/config/routes.rb b/config/routes.rb index cdc93fe..81b3caa 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,10 +1,8 @@ Apollo::Application.routes.draw do - resources :layers - - get "logout" => "sessions#destroy", :as => "logout" get "login" => "sessions#new", :as => "login" + resources :layers resources :users resources :sessions resources :password_resets