@@ -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,16 @@ 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' | |||
group :development do | |||
gem 'meta_request' | |||
gem 'better_errors' | |||
gem 'binding_of_caller' | |||
end |
@@ -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,10 +32,13 @@ 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) | |||
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) | |||
@@ -42,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) | |||
@@ -81,16 +87,10 @@ 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) | |||
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,12 +101,13 @@ 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) | |||
rack (>= 0.4) | |||
rack-contrib (1.1.0) | |||
rack (>= 0.9.1) | |||
rack-ssl (1.3.3) | |||
rack | |||
rack-test (0.6.2) | |||
@@ -160,14 +161,16 @@ PLATFORMS | |||
ruby | |||
DEPENDENCIES | |||
bson_ext | |||
activerecord-postgresql-adapter | |||
better_errors | |||
binding_of_caller | |||
coffee-rails (~> 3.2.1) | |||
feedzirra | |||
haml-rails | |||
htmlentities | |||
jquery-rails | |||
mm-multi-parameter-attributes | |||
mongo_mapper | |||
meta_request | |||
pg | |||
rails (= 3.2.12) | |||
sass-rails (~> 3.2.3) | |||
sorcery | |||
@@ -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/ |
@@ -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/ |
@@ -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 } | |||
@@ -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" } | |||
@@ -87,12 +103,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 |
@@ -0,0 +1,85 @@ | |||
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]) | |||
@feed = Feed.new | |||
@feed.new_layer_id = @layer.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 |
@@ -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', | |||
@@ -0,0 +1,2 @@ | |||
module LayersHelper | |||
end |
@@ -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 => [ | |||
{ | |||
@@ -1,57 +1,45 @@ | |||
class Feed | |||
include MongoMapper::Document | |||
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 | |||
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 | |||
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| | |||
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 | |||
end | |||
attrs = { | |||
:title => e.title, | |||
:url => e.url, | |||
@@ -60,20 +48,15 @@ class Feed | |||
: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 |
@@ -0,0 +1,4 @@ | |||
class Layer < ActiveRecord::Base | |||
attr_accessible :name | |||
has_and_belongs_to_many :feeds | |||
end |
@@ -1,26 +1,70 @@ | |||
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']] | |||
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, 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 | |||
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 | |||
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 | |||
ENDQUERY | |||
) | |||
end | |||
end |
@@ -1,11 +1,4 @@ | |||
class User | |||
include MongoMapper::Document | |||
key :email, String | |||
key :crypted_password, String | |||
key :salt, String | |||
timestamps! | |||
class User < ActiveRecord::Base | |||
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 |
@@ -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 | |||
@@ -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") | |||
@@ -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' |
@@ -0,0 +1,7 @@ | |||
%h1 Editing layer | |||
= render 'form' | |||
= link_to 'Show', @layer | |||
\| | |||
= link_to 'Back', layers_path |
@@ -0,0 +1,10 @@ | |||
%h1 Layers | |||
= link_to 'New Layer', new_layer_path, :class => 'button' | |||
%table | |||
- @layers.each do |layer| | |||
%tr | |||
%td= link_to layer.name, layer | |||
%td= link_to 'Edit', edit_layer_path(layer) | |||
%td= link_to 'Delete', layer, :method => :delete, :data => { :confirm => 'Are you sure?' } |
@@ -0,0 +1,5 @@ | |||
%h1 New layer | |||
= render 'form' | |||
= link_to 'Back', layers_path |
@@ -0,0 +1,51 @@ | |||
%h1 | |||
Layer: | |||
= @layer.name | |||
%p | |||
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) | |||
\| | |||
= link_to 'Back', layers_path |
@@ -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") |
@@ -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 | |||
@@ -15,7 +16,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,10 +72,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 | |||
end |
@@ -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 |
@@ -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'] %> |
@@ -2,6 +2,7 @@ Apollo::Application.routes.draw do | |||
get "logout" => "sessions#destroy", :as => "logout" | |||
get "login" => "sessions#new", :as => "login" | |||
resources :layers | |||
resources :users | |||
resources :sessions | |||
resources :password_resets | |||
@@ -65,7 +66,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" | |||
@@ -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 |
@@ -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 |
@@ -0,0 +1,6 @@ | |||
class AddGuidToPostsRemoveGuidFromFeeds < ActiveRecord::Migration | |||
def change | |||
remove_column :feeds, :guid | |||
add_column :posts, :guid, :string | |||
end | |||
end |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -0,0 +1,63 @@ | |||
# 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 => 20130228150425) do | |||
create_table "feeds", :force => true do |t| | |||
t.string "title" | |||
t.string "feed_url" | |||
t.string "url" | |||
t.string "description" | |||
t.string "generator" | |||
t.datetime "created_at", :null => false | |||
t.datetime "updated_at", :null => false | |||
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" | |||
t.string "author" | |||
t.text "summary" | |||
t.text "content" | |||
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| | |||
t.string "email" | |||
t.string "crypted_password" | |||
t.string "salt" | |||
t.datetime "created_at", :null => false | |||
t.datetime "updated_at", :null => false | |||
end | |||
end |
@@ -0,0 +1,7 @@ | |||
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html | |||
one: | |||
name: MyString | |||
two: | |||
name: MyString |
@@ -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 |
@@ -0,0 +1,4 @@ | |||
require 'test_helper' | |||
class LayersHelperTest < ActionView::TestCase | |||
end |
@@ -0,0 +1,7 @@ | |||
require 'test_helper' | |||
class LayerTest < ActiveSupport::TestCase | |||
# test "the truth" do | |||
# assert true | |||
# end | |||
end |