merge from upstream

This commit is contained in:
Mackenzie Morgan
2015-01-27 22:35:19 -05:00
384 changed files with 3509 additions and 2124 deletions

1
.rspec
View File

@@ -1 +1,2 @@
--color
--require spec_helper

View File

@@ -1 +1 @@
2.1.2
2.1.5

View File

@@ -1,12 +1,34 @@
---
sudo: false
language: ruby
env: GROWSTUFF_SITE_NAME="Growstuff (travis)" RAILS_SECRET_TOKEN='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
bundler_args: --without development production staging
cache: bundler
env:
matrix:
- GROWSTUFF_SITE_NAME="Growstuff (travis)" RAILS_SECRET_TOKEN='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
global:
secure: "Z5TpM2jEX4UCvNePnk/LwltQX48U2u9BRc+Iypr1x9QW2o228QJhPIOH39a8RMUrepGnkQIq9q3ZRUn98RfrJz1yThtlNFL3NmzdQ57gKgjGwfpa0e4Dwj/ZJqV2D84tDGjvdVYLP7zzaYZxQcwk/cgNpzKf/jq97HLNP7CYuf4="
bundler_args: "--without development production staging"
rvm:
- 2.1.2
- 2.1.5
before_script:
- psql -c 'create database growstuff_test;' -U postgres
- psql -c 'create database growstuff_test;' -U postgres
script:
- bundle exec rake db:migrate --trace
- bundle exec rspec spec/
- bundle exec rake db:migrate --trace
- bundle exec rspec spec/
before_deploy:
- bundle exec script/heroku_maintenance.rb on
deploy:
provider: heroku
api_key:
secure: WrQxf0fEKkCdXrjcejurobOnNNz3he4dDwjBbToXbQTQNDObPp7NetJrLsfM8FiUFEeOuvhIHHiDQtMvY720zGGAGxDptvgFS+0QHCUqoTRZA/yFfUmHlG2jROXTzk5uVK0AE4k6Ion5kX8+mM0EnMT/7u+MTFiukrJctSiEXfg=
on:
repo: Growstuff/growstuff
app:
dev: growstuff-staging
travis_deploy: tranquil-basin-3130
travis_containers: tranquil-basin-3130
run:
- "rake db:migrate"
- "script/deploy-tasks.sh"
- restart
after_deploy:
- bundle exec script/heroku_maintenance.rb off

View File

@@ -1,8 +1,8 @@
Thanks for contributing to Growstuff!
Please include the following information in your pull request:
When you create a pull request, please include the following:
* A link to the [Pivotal Tracker](http://tracker.growstuff.org/) task to which it relates.
* Mention the issue it solves (eg. #123)
* Your code should follow our [Coding style guide](http://wiki.growstuff.org/index.php/Coding_style_guide)
* Make sure you have automated tests for your work, where possible.
* Add your name (and that of your pair partner, if any) to [CONTRIBUTORS.md](CONTRIBUTORS.md).

View File

@@ -11,10 +11,11 @@ submit the change with your pull request.
- Alex Bayley / [Skud](https://github.com/Skud)
- Cesy / [cesy](https://github.com/cesy)
- Miles Gould / [pozorvlak](https://github.com/pozorvlak)
- Joseph Caudle / [jcaudle](https://github.com/jcaudle)
- Taylor Griffin / [tygriffin](https://github.com/tygriffin)
## Contributors
- Joseph Caudle / [jcaudle](https://github.com/jcaudle)
- Ricky Amianym / [amianym](https://github.com/amianym)
- Juliet Kemp / [julietk](https://github.com/julietk)
- Federico Mena Quintero / [federicomenaquintero](https://github.com/federicomenaquintero)
@@ -38,10 +39,8 @@ submit the change with your pull request.
- Yaw Boakye / [yawboakye](https://github.com/yawboakye)
- Ryan Clark / [IAMRYO](https://github.com/IAMRYO)
- Marty Hines / [martyhines](https://github.com/martyhines)
- Mackenzie "Maco" King / [maco](https://github.com/maco)
- Amelia Greenhall / [ameliagreenhall](https://github.com/ameliagreenhall)
- Barb Natali / [barbnatali](https://github.com/barbnatali)
- Taylor Griffin / [tygriffin](https://github.com/tygriffin)
- Marlena Compton / [Marlena](https://github.com/marlena)
- Elizabeth A. Kari / [catfriend](https://github.com/catfriend)
- Cheri Allen / [cherimarie](https://github.com/cherimarie)
@@ -50,4 +49,7 @@ submit the change with your pull request.
- Emma Winston / [emmawinston](https://github.com/emmawinston)
- Kevin Rio / [krio](https://github.com/krio)
- Yoong Kang Lim / [yoongkang](https://github.com/yoongkang)
- Kevin Yang / [kevieyang](https://github.com/kevieyang)
- Justin Hamman / [juzham](https://github.com/juzham)
- Rocky Jaiswal / [rocky-jaiswal](https://github.com/rocky-jaiswal)

157
Gemfile
View File

@@ -1,92 +1,52 @@
source 'https://rubygems.org'
ruby "2.1.2"
ruby '2.1.5'
gem 'rails', '4.1.9'
gem 'bundler', '>=1.1.5'
gem 'rails', '3.2.13'
gem 'rack', '~>1.4.5'
gem 'json', '~>1.7.7'
gem 'sass-rails', '~> 4.0.4'
gem 'coffee-rails', '~> 4.1.0'
gem 'haml'
# Another CSS preprocessor, used for Bootstrap overrides
gem 'less', '~>2.5.0'
gem 'less-rails', '~> 2.5.0'
# CSS framework
gem 'less-rails-bootstrap', '~> 3.2.0'
gem 'uglifier', '~> 2.5.3' # JavaScript compressor
gem 'jquery-rails'
gem 'jquery-ui-rails', '~> 5.0.2'
gem 'js-routes' # provides access to Rails routes in Javascript
gem 'flickraw'
gem 'leaflet-rails'
gem 'leaflet-markercluster-rails'
gem 'unicorn' # http server
gem 'unicorn' # http server
gem 'pg'
gem 'figaro' # for handling config via ENV variables
gem 'cancan' # for checking member privileges
gem 'gibbon' # for Mailchimp newsletter subscriptions
gem 'csv_shaper' # CSV export
gem 'figaro' # for handling config via ENV variables
gem 'cancancan', '~> 1.9' # for checking member privileges
gem 'gibbon' # for Mailchimp newsletter subscriptions
gem 'csv_shaper' # CSV export
# vendored activemerchant for testing- needed for bogus paypal
# gateway monkeypatch
gem 'activemerchant', '1.33.0',
:path => 'vendor/gems/activemerchant-1.33.0',
:path => 'vendor/gems/activemerchant-1.33.0',
:require => 'active_merchant'
gem 'active_utils', '1.0.5',
:path => 'vendor/gems/active_utils-1.0.5'
:path => 'vendor/gems/active_utils-1.0.5'
group :production, :staging do
gem 'newrelic_rpm'
gem 'dalli'
gem 'memcachier'
gem 'rails_12factor' # supresses heroku plugin injection
end
# Gems used only for assets and not required
# in production environments by default.
group :assets do
# CSS preprocessor, used for app/assets/stylesheets/application.css
gem 'sass-rails', '~> 3.2.3'
# CoffeeScript is a Python-like language that compiles to JavaScript
gem 'coffee-rails', '~> 3.2.1'
# less-rails depends on a JavaScript engine; we use therubyracer.
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
# long term, we'll probably want node.js for performance, but this will do
# for now as it's easier for new people to install
gem "therubyracer", "~> 0.12", :platforms => :ruby
# libv8 is needed by therubyracer and is a bit finicky
gem 'libv8', '3.16.14.3'
# Another CSS preprocessor, used for Bootstrap overrides
gem "less", '~>2.5.0'
gem "less-rails", '~> 2.5.0'
# CSS framework
gem "less-rails-bootstrap", '~> 3.2.0'
gem 'uglifier', '>= 1.0.3' # JavaScript compressor
gem 'compass-rails', '~> 1.0.3' # Yet Another CSS framework
end
gem 'jquery-rails'
gem 'jquery-ui-rails'
gem 'js-routes' # provides access to Rails routes in Javascript
gem 'flickraw'
# To use ActiveModel has_secure_password
# gem 'bcrypt-ruby', '~> 3.0.0'
# To use Jbuilder templates for JSON
# gem 'jbuilder'
# Use unicorn as the app server
# gem 'unicorn'
group :development do
# A debugger and irb alternative. Pry doesn't play nice
# with unicorn, so start a Webrick server when debugging
# with Pry
gem 'pry'
gem 'better_errors'
gem 'binding_of_caller'
gem 'letter_opener'
end
# less-rails depends on a JavaScript engine; we use therubyracer.
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
# long term, we'll probably want node.js for performance, but this will do
# for now as it's easier for new people to install
gem 'therubyracer', '~> 0.12', :platforms => :ruby
# libv8 is needed by therubyracer and is a bit finicky
gem 'libv8', '3.16.14.7'
# Markdown formatting for updates etc
gem 'bluecloth'
@@ -95,10 +55,10 @@ gem 'bluecloth'
gem 'will_paginate', '~> 3.0'
# user signup/login/etc
gem 'devise', '~> 3.2.0'
gem 'devise', '~> 3.4.1'
# nicely formatted URLs
gem 'friendly_id', '~> 4.0.10'
gem 'friendly_id', '~> 5.0.4'
# gravatars
gem 'gravatar-ultimate'
@@ -118,16 +78,39 @@ gem 'omniauth-flickr', '>= 0.0.15'
gem 'rake', '>= 10.0.0'
group :development, :test do
gem 'byebug' # debugging
gem 'haml-rails' # HTML templating language
gem 'rspec-rails', '~> 2.12.1' # unit testing framework
gem 'database_cleaner', '~> 1.3.0'
gem 'webrat' # provides HTML matchers for view tests
gem 'factory_girl_rails', '~> 4.0' # for creating test data
gem 'coveralls', require: false # coverage analysis
gem 'capybara' # integration tests
gem 'capybara-email' # integration tests for email
gem 'poltergeist', '~> 1.5.1' # for headless JS testing
gem 'i18n-tasks' # adds tests for finding missing and unused translations
group :production, :staging do
gem 'newrelic_rpm'
gem 'dalli'
gem 'memcachier'
gem 'rails_12factor' # supresses heroku plugin injection
end
group :development do
# A debugger and irb alternative. Pry doesn't play nice
# with unicorn, so start a Webrick server when debugging
# with Pry
gem 'pry'
gem 'better_errors'
gem 'binding_of_caller'
gem 'letter_opener'
gem 'quiet_assets'
end
group :development, :test do
gem 'haml-rails' # HTML templating language
gem 'rspec-rails', '~> 3.1.0' # unit testing framework
gem 'rspec-activemodel-mocks'
gem 'byebug' # debugging
gem 'database_cleaner', '~> 1.3.0'
gem 'webrat' # provides HTML matchers for view tests
gem 'factory_girl_rails', '~> 4.5.0' # for creating test data
gem 'coveralls', require: false # coverage analysis
gem 'capybara' # integration tests
gem 'capybara-email' # integration tests for email
gem 'poltergeist', '~> 1.5.1' # for headless JS testing
gem 'i18n-tasks' # adds tests for finding missing and unused translations
end
group :travis do
gem 'heroku-api'
end

View File

@@ -20,35 +20,34 @@ PATH
GEM
remote: https://rubygems.org/
specs:
actionmailer (3.2.13)
actionpack (= 3.2.13)
mail (~> 2.5.3)
actionpack (3.2.13)
activemodel (= 3.2.13)
activesupport (= 3.2.13)
builder (~> 3.0.0)
actionmailer (4.1.9)
actionpack (= 4.1.9)
actionview (= 4.1.9)
mail (~> 2.5, >= 2.5.4)
actionpack (4.1.9)
actionview (= 4.1.9)
activesupport (= 4.1.9)
rack (~> 1.5.2)
rack-test (~> 0.6.2)
actionview (4.1.9)
activesupport (= 4.1.9)
builder (~> 3.1)
erubis (~> 2.7.0)
journey (~> 1.0.4)
rack (~> 1.4.5)
rack-cache (~> 1.2)
rack-test (~> 0.6.1)
sprockets (~> 2.2.1)
activemodel (3.2.13)
activesupport (= 3.2.13)
builder (~> 3.0.0)
activerecord (3.2.13)
activemodel (= 3.2.13)
activesupport (= 3.2.13)
arel (~> 3.0.2)
tzinfo (~> 0.3.29)
activeresource (3.2.13)
activemodel (= 3.2.13)
activesupport (= 3.2.13)
activesupport (3.2.13)
i18n (= 0.6.1)
multi_json (~> 1.0)
activemodel (4.1.9)
activesupport (= 4.1.9)
builder (~> 3.1)
activerecord (4.1.9)
activemodel (= 4.1.9)
activesupport (= 4.1.9)
arel (~> 5.0.0)
activesupport (4.1.9)
i18n (~> 0.6, >= 0.6.9)
json (~> 1.7, >= 1.7.7)
minitest (~> 5.1)
thread_safe (~> 0.1)
tzinfo (~> 1.1)
addressable (2.3.6)
arel (3.0.3)
arel (5.0.1.20140414130214)
bcrypt (3.1.9)
better_errors (2.0.0)
coderay (>= 1.0.0)
@@ -59,12 +58,12 @@ GEM
bluecloth (2.2.0)
bootstrap-datepicker-rails (1.3.0.2)
railties (>= 3.0)
builder (3.0.4)
builder (3.2.2)
byebug (3.5.1)
columnize (~> 0.8)
debugger-linecache (~> 1.2)
slop (~> 3.6)
cancan (1.6.10)
cancancan (1.9.2)
capybara (2.4.4)
mime-types (>= 1.16)
nokogiri (>= 1.3.3)
@@ -74,24 +73,17 @@ GEM
capybara-email (2.4.0)
capybara (~> 2.4)
mail
chunky_png (1.3.3)
cliver (0.3.2)
coderay (1.1.0)
coffee-rails (3.2.2)
coffee-rails (4.1.0)
coffee-script (>= 2.2.0)
railties (~> 3.2.0)
railties (>= 4.0.0, < 5.0)
coffee-script (2.3.0)
coffee-script-source
execjs
coffee-script-source (1.8.0)
columnize (0.8.9)
columnize (0.9.0)
commonjs (0.2.7)
compass (0.12.7)
chunky_png (~> 1.2)
fssm (>= 0.2.7)
sass (~> 3.2.19)
compass-rails (1.0.3)
compass (>= 0.12.2, < 0.14)
coveralls (0.7.1)
multi_json (~> 1.3)
rest-client
@@ -104,19 +96,21 @@ GEM
database_cleaner (1.3.0)
debug_inspector (0.0.2)
debugger-linecache (1.2.0)
devise (3.2.4)
devise (3.4.1)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 3.2.6, < 5)
responders
thread_safe (~> 0.1)
warden (~> 1.2.3)
diff-lcs (1.1.3)
diff-lcs (1.2.5)
docile (1.1.5)
easy_translate (0.5.0)
json
thread
thread_safe
erubis (2.7.0)
excon (0.43.0)
execjs (2.2.2)
factory_girl (4.5.0)
activesupport (>= 3.0.0)
@@ -126,29 +120,38 @@ GEM
figaro (1.0.0)
thor (~> 0.14)
flickraw (0.9.8)
friendly_id (4.0.10.1)
activerecord (>= 3.0, < 4.0)
fssm (0.2.10)
friendly_id (5.0.4)
activerecord (>= 4.0.0)
gibbon (1.1.4)
httparty
multi_json (>= 1.3.4)
gravatar-ultimate (2.0.0)
activesupport (>= 2.3.14)
rack
haml (4.0.5)
haml (4.1.0.beta.1)
tilt
haml-rails (0.4)
actionpack (>= 3.1, < 4.1)
activesupport (>= 3.1, < 4.1)
haml (>= 3.1, < 4.1)
railties (>= 3.1, < 4.1)
hashie (3.3.1)
haml-rails (0.6.0)
actionpack (>= 4.0.1)
activesupport (>= 4.0.1)
haml (>= 3.1, < 5.0)
html2haml (>= 1.0.1)
railties (>= 4.0.1)
hashie (3.3.2)
heroku-api (0.3.22)
excon (~> 0.38)
multi_json (~> 1.8)
highline (1.6.21)
hike (1.2.3)
httparty (0.11.0)
multi_json (~> 1.0)
hpricot (0.8.6)
html2haml (1.0.1)
erubis (~> 2.7.0)
haml (>= 4.0.0.rc.1)
hpricot (~> 0.8.6)
ruby_parser (~> 3.1.1)
httparty (0.13.3)
json (~> 1.8)
multi_xml (>= 0.5.2)
i18n (0.6.1)
i18n (0.7.0)
i18n-tasks (0.7.8)
activesupport
easy_translate (>= 0.5.0)
@@ -158,16 +161,15 @@ GEM
slop (>= 3.5.0)
term-ansicolor
terminal-table
journey (1.0.4)
jquery-rails (3.1.2)
railties (>= 3.0, < 5.0)
thor (>= 0.14, < 2.0)
jquery-ui-rails (4.1.2)
railties (>= 3.1.0)
jquery-ui-rails (5.0.3)
railties (>= 3.2.16)
js-routes (0.9.9)
railties (>= 3.2)
sprockets-rails
json (1.7.7)
json (1.8.2)
kgio (2.9.2)
launchy (2.4.3)
addressable (~> 2.3)
@@ -181,21 +183,21 @@ GEM
less (~> 2.5.0)
less-rails-bootstrap (3.2.0)
less-rails (~> 2.5.0)
letter_opener (1.2.0)
letter_opener (1.3.0)
launchy (~> 2.2)
libv8 (3.16.14.3)
mail (2.5.4)
mime-types (~> 1.16)
treetop (~> 1.4.8)
libv8 (3.16.14.7)
mail (2.6.3)
mime-types (>= 1.16, < 3)
memcachier (0.0.2)
method_source (0.8.2)
mime-types (1.25.1)
mime-types (2.4.3)
mini_portile (0.6.1)
minitest (5.5.1)
multi_json (1.10.1)
multi_xml (0.5.5)
netrc (0.8.0)
newrelic_rpm (3.9.6.257)
nokogiri (1.6.4.1)
netrc (0.10.0)
newrelic_rpm (3.9.8.273)
nokogiri (1.6.5)
mini_portile (~> 0.6.0)
oauth (0.4.7)
omniauth (1.2.2)
@@ -216,75 +218,87 @@ GEM
cliver (~> 0.3.1)
multi_json (~> 1.0)
websocket-driver (>= 0.2.0)
polyglot (0.3.5)
pry (0.10.1)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
slop (~> 3.4)
rack (1.4.5)
rack-cache (1.2)
rack (>= 0.4)
rack-ssl (1.3.4)
rack
rack-test (0.6.2)
quiet_assets (1.1.0)
railties (>= 3.1, < 5.0)
rack (1.5.2)
rack-test (0.6.3)
rack (>= 1.0)
rails (3.2.13)
actionmailer (= 3.2.13)
actionpack (= 3.2.13)
activerecord (= 3.2.13)
activeresource (= 3.2.13)
activesupport (= 3.2.13)
bundler (~> 1.0)
railties (= 3.2.13)
rails (4.1.9)
actionmailer (= 4.1.9)
actionpack (= 4.1.9)
actionview (= 4.1.9)
activemodel (= 4.1.9)
activerecord (= 4.1.9)
activesupport (= 4.1.9)
bundler (>= 1.3.0, < 2.0)
railties (= 4.1.9)
sprockets-rails (~> 2.0)
rails_12factor (0.0.3)
rails_serve_static_assets
rails_stdout_logging
rails_serve_static_assets (0.0.2)
rails_stdout_logging (0.0.3)
railties (3.2.13)
actionpack (= 3.2.13)
activesupport (= 3.2.13)
rack-ssl (~> 1.3.2)
railties (4.1.9)
actionpack (= 4.1.9)
activesupport (= 4.1.9)
rake (>= 0.8.7)
rdoc (~> 3.4)
thor (>= 0.14.6, < 2.0)
thor (>= 0.18.1, < 2.0)
raindrops (0.13.0)
rake (10.3.2)
rdoc (3.12.2)
json (~> 1.4)
rake (10.4.2)
ref (1.0.5)
responders (1.1.2)
railties (>= 3.2, < 4.2)
rest-client (1.7.2)
mime-types (>= 1.16, < 3.0)
netrc (~> 0.7)
rspec-core (2.12.2)
rspec-expectations (2.12.1)
diff-lcs (~> 1.1.3)
rspec-mocks (2.12.2)
rspec-rails (2.12.2)
rspec-activemodel-mocks (1.0.1)
activemodel (>= 3.0)
activesupport (>= 3.0)
rspec-mocks (>= 2.99, < 4.0)
rspec-core (3.1.7)
rspec-support (~> 3.1.0)
rspec-expectations (3.1.2)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.1.0)
rspec-mocks (3.1.3)
rspec-support (~> 3.1.0)
rspec-rails (3.1.0)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
rspec-core (~> 2.12.0)
rspec-expectations (~> 2.12.0)
rspec-mocks (~> 2.12.0)
rspec-core (~> 3.1.0)
rspec-expectations (~> 3.1.0)
rspec-mocks (~> 3.1.0)
rspec-support (~> 3.1.0)
rspec-support (3.1.2)
ruby_parser (3.1.3)
sexp_processor (~> 4.1)
sass (3.2.19)
sass-rails (3.2.6)
railties (~> 3.2.0)
sass (>= 3.1.10)
tilt (~> 1.3)
sass-rails (4.0.5)
railties (>= 4.0.0, < 5.0)
sass (~> 3.2.2)
sprockets (~> 2.8, < 3.0)
sprockets-rails (~> 2.0)
sexp_processor (4.4.4)
simplecov (0.9.1)
docile (~> 1.1.0)
multi_json (~> 1.0)
simplecov-html (~> 0.8.0)
simplecov-html (0.8.0)
slop (3.6.0)
sprockets (2.2.3)
sprockets (2.12.3)
hike (~> 1.2)
multi_json (~> 1.0)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
sprockets-rails (0.0.1)
sprockets (>= 1.0.2)
sprockets-rails (2.2.2)
actionpack (>= 3.0)
activesupport (>= 3.0)
sprockets (>= 2.8, < 4.0)
term-ansicolor (1.3.0)
tins (~> 1.0)
terminal-table (1.4.5)
@@ -296,13 +310,11 @@ GEM
thread_safe (0.3.4)
tilt (1.4.1)
tins (1.3.3)
treetop (1.4.15)
polyglot
polyglot (>= 0.3.1)
tzinfo (0.3.42)
uglifier (2.2.1)
tzinfo (1.2.2)
thread_safe (~> 0.1)
uglifier (2.5.3)
execjs (>= 0.3.0)
multi_json (~> 1.0, >= 1.0.2)
json (>= 1.8.0)
unicorn (4.8.3)
kgio (~> 2.6)
rack
@@ -313,7 +325,9 @@ GEM
nokogiri (>= 1.2.0)
rack (>= 1.0)
rack-test (>= 0.5.3)
websocket-driver (0.4.0)
websocket-driver (0.5.0)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.0)
will_paginate (3.0.7)
xpath (2.0.0)
nokogiri (~> 1.3)
@@ -330,37 +344,36 @@ DEPENDENCIES
bootstrap-datepicker-rails
bundler (>= 1.1.5)
byebug
cancan
cancancan (~> 1.9)
capybara
capybara-email
coffee-rails (~> 3.2.1)
compass-rails (~> 1.0.3)
coffee-rails (~> 4.1.0)
coveralls
csv_shaper
dalli
database_cleaner (~> 1.3.0)
devise (~> 3.2.0)
factory_girl_rails (~> 4.0)
devise (~> 3.4.1)
factory_girl_rails (~> 4.5.0)
figaro
flickraw
friendly_id (~> 4.0.10)
friendly_id (~> 5.0.4)
geocoder!
gibbon
gravatar-ultimate
haml
haml-rails
heroku-api
i18n-tasks
jquery-rails
jquery-ui-rails
jquery-ui-rails (~> 5.0.2)
js-routes
json (~> 1.7.7)
leaflet-markercluster-rails
leaflet-rails
less (~> 2.5.0)
less-rails (~> 2.5.0)
less-rails-bootstrap (~> 3.2.0)
letter_opener
libv8 (= 3.16.14.3)
libv8 (= 3.16.14.7)
memcachier
newrelic_rpm
omniauth
@@ -369,14 +382,15 @@ DEPENDENCIES
pg
poltergeist (~> 1.5.1)
pry
rack (~> 1.4.5)
rails (= 3.2.13)
quiet_assets
rails (= 4.1.9)
rails_12factor
rake (>= 10.0.0)
rspec-rails (~> 2.12.1)
sass-rails (~> 3.2.3)
rspec-activemodel-mocks
rspec-rails (~> 3.1.0)
sass-rails (~> 4.0.4)
therubyracer (~> 0.12)
uglifier (>= 1.0.3)
uglifier (~> 2.5.3)
unicorn
webrat
will_paginate (~> 3.0)

View File

@@ -16,18 +16,42 @@ encourage participation from people of all backgrounds and skill levels.
## Important links
* [Wiki](http://wiki.growstuff.org/) (general documentation)
* [Task tracker](http://tracker.growstuff.org/) (recent and upcoming work, bugs, etc)
* [Issues](http://github.com/Growstuff/growstuff/issues) (features we're
working on, known bugs, etc)
* [Discussion forums](http://wiki.growstuff.org/index.php/Discussion_forums) (mailing lists, IRC, etc)
* [Wiki](http://wiki.growstuff.org/) (general documentation)
## For developers
## For coders
Growstuff is built in Ruby on Rails and also uses JavaScript for
frontend features. We welcome contributions -- see
[CONTRIBUTING](CONTRIBUTING.md) for details.
* Start by looking at our [task tracker](http://tracker.growstuff.org/) for something to work on.
* Drop in to one of our [discussion forums](http://wiki.growstuff.org/index.php/Discussion_forums) to talk to our team about it.
* To set up your development environment, see [Getting started](http://wiki.growstuff.org/index.php/Development/Getting_Started).
* We encourage [pair programming](http://wiki.growstuff.org/index.php/Pairing), especially for newer developers.
* We encourage [pair programming](http://wiki.growstuff.org/index.php/Pairing), especially for newer developers. [Find a pair programming partner.](http://talk.growstuff.org/t/find-a-pair-programming-partner/13)
* Drop in to one of our [discussion forums](http://wiki.growstuff.org/index.php/Discussion_forums) to chat to other developers, get help, etc.
* You may also be interested in our [API](http://wiki.growstuff.org/index.php/API).
## For designers, writers, researchers, data wranglers, and other contributors
There are heaps of ways to get involved and contribute no matter what
your skills and interests.
You might like to check out:
* The [Get Involved](http://wiki.growstuff.org/index.php/Get_involved)
page on our wiki, which has lots of detail for different areas
* [Growstuff Talk](http://talk.growstuff.org/) especially the [Idea category](http://talk.growstuff.org/c/idea)
Here on Github, you might find these useful:
* [needs: design](https://github.com/Growstuff/growstuff/labels/needs:%20design) - tasks requiring high-level design
* [needs: visual design](https://github.com/Growstuff/growstuff/labels/needs:%20visual design) - tasks requiring visual/graphical design
* [needs: documentation](https://github.com/Growstuff/growstuff/labels/needs:%20documentation)
* [needs: data](https://github.com/Growstuff/growstuff/labels/needs:%20data) - tasks requiring data entry, data design, data import, or similar
Feel free to comment on any of the issues you find there, or open up a broader conversation on [Growstuff Talk](http://talk.growstuff.org).
## Contact
For more information about this project, contact [info@growstuff.org](mailto:info@growstuff.org).

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 613 B

View File

@@ -15,7 +15,7 @@
//= require js-routes
//= require jquery
//= require jquery_ujs
//= require jquery.ui.autocomplete
//= require jquery-ui/autocomplete
//= require twitter/bootstrap
//= require_tree .
//= require bootstrap-datepicker

View File

@@ -3,7 +3,7 @@
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
* the top of the compiled file, but it's generally better to create a new file per style scope.
*= require_self
*= require jquery.ui.autocomplete
*= require jquery-ui/autocomplete
*= require bootstrap-datepicker
*= require leaflet
*= require leaflet.markercluster

View File

@@ -1,3 +1,5 @@
@import "twitter/bootstrap/bootstrap";
@import "custom_bootstrap/variables";
// this padding needs to be done before the responsive stuff is imported
@@ -122,7 +124,7 @@ p.stats {
color: @brown;
}
.crop-thumbnail {
.photo-thumbnail {
position:relative;
padding:0;
img {
@@ -149,16 +151,56 @@ p.stats {
}
}
.member-thumbnail {
img {
height: 85px;
width: 85px;
max-width: 85px
}
}
.thumbnail {
border: none;
text-align: center;
margin-bottom: 1.5em;
.member-thumbnail {
text-align: left;
img {
height: 85px;
width: 85px;
max-width: 85px
}
}
.crop-thumbnail {
height: 220px;
.cropinfo {
display: inline-block;
max-width: 100%;
white-space: nowrap;
line-height: 1em;
padding-bottom: 2px;
.cropname {
overflow: hidden;
text-overflow: ellipsis;
}
.scientificname {
font-size: small;
font-style: italic;
overflow: hidden;
text-overflow: ellipsis;
}
.plantingcount {
font-size: small;
}
}
.crop-name a {
padding-top: 2px;
}
.scientific-name small {
margin-bottom: -2px;
}
}
}
li.crop-hierarchy {
@@ -174,31 +216,48 @@ li.crop-hierarchy {
margin: 40px 0px 0px 0px !important;
}
// navbar centering
footer .navbar .nav {
float: none;
display: inline-block;
*display: inline;
/* ie7 fix */
*zoom: 1;
/* hasLayout ie7 trigger */
vertical-align: top;
> li {
float: none;
display: inline-block;
*display: inline;
/* ie7 fix */
*zoom: 1;
/* hasLayout ie7 trigger */
vertical-align: top;
// footer
footer {
#contact, #about-growstuff, #policies {
text-align: left;
padding-top: 1em;
padding-bottom: 2em;
ul {
list-style-type: none;
list-style-position: outside;
padding-left: 0px;
margin-left: 0px;
}
a {
color: @navbar-default-link-color;
text-decoration: none;
}
a:hover {
color: @navbar-default-link-hover-color;
}
a:active {
color: @navbar-default-link-active-color;
}
}
.navbar-bottom.navbar {
border-radius: 0;
}
}
.navbar-bottom.navbar {
text-align: center;
border-radius: 0;
// ensure footer is pushed to bottom of browser window
#maincontainer {
min-height: 80%;
}
html, body {
height: 100%;
}
//
.crop-image, .member-image {
width: 100%;
height: 100%;

View File

@@ -1,5 +1,7 @@
class AccountTypesController < ApplicationController
before_filter :authenticate_member!
load_and_authorize_resource
# GET /account_types
def index
@account_types = AccountType.all
@@ -34,7 +36,7 @@ class AccountTypesController < ApplicationController
# POST /account_types
def create
@account_type = AccountType.new(params[:account_type])
@account_type = AccountType.new(account_type_params)
respond_to do |format|
if @account_type.save
@@ -50,7 +52,7 @@ class AccountTypesController < ApplicationController
@account_type = AccountType.find(params[:id])
respond_to do |format|
if @account_type.update_attributes(params[:account_type])
if @account_type.update(account_type_params)
format.html { redirect_to @account_type, notice: 'Account type was successfully updated.' }
else
format.html { render action: "edit" }
@@ -67,4 +69,10 @@ class AccountTypesController < ApplicationController
format.html { redirect_to account_types_url, notice: 'Account type was successfully deleted.' }
end
end
private
def account_type_params
params.require(:account_type).permit(:is_paid, :is_permanent_paid, :name)
end
end

View File

@@ -1,5 +1,7 @@
class AccountsController < ApplicationController
before_filter :authenticate_member!
load_and_authorize_resource
# GET /accounts
def index
@accounts = Account.all
@@ -28,7 +30,7 @@ class AccountsController < ApplicationController
@account = Account.find(params[:id])
respond_to do |format|
if @account.update_attributes(params[:account])
if @account.update(params[:account])
format.html { redirect_to @account, notice: 'Account detail was successfully updated.' }
else
format.html { render action: "edit" }
@@ -36,4 +38,10 @@ class AccountsController < ApplicationController
end
end
private
def account_params
params.require(:account).permit(:account_type_id, :member_id, :paid_until)
end
end

View File

@@ -1,4 +1,5 @@
class AlternateNamesController < ApplicationController
before_filter :authenticate_member!, :except => [:index, :show]
load_and_authorize_resource
# GET /alternate_names
@@ -44,7 +45,7 @@ class AlternateNamesController < ApplicationController
# POST /alternate_names.json
def create
params[:alternate_name][:creator_id] = current_member.id
@alternate_name = AlternateName.new(params[:alternate_name])
@alternate_name = AlternateName.new(alternate_name_params)
respond_to do |format|
if @alternate_name.save
@@ -63,7 +64,7 @@ class AlternateNamesController < ApplicationController
@alternate_name = AlternateName.find(params[:id])
respond_to do |format|
if @alternate_name.update_attributes(params[:alternate_name])
if @alternate_name.update(alternate_name_params)
format.html { redirect_to @alternate_name.crop, notice: 'Alternate name was successfully updated.' }
format.json { head :no_content }
else
@@ -87,4 +88,10 @@ class AlternateNamesController < ApplicationController
format.json { head :no_content }
end
end
private
def alternate_name_params
params.require(:alternate_name).permit(:crop_id, :name, :creator_id)
end
end

View File

@@ -43,4 +43,36 @@ class ApplicationController < ActionController::Base
I18n.available_locales.map(&:to_s).include?(parsed_locale) ? parsed_locale : nil
end
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) do |member|
member.permit(:login_name, :email, :password, :password_confirmation,
:remember_me, :login,
# terms of service
:tos_agreement,
# profile stuff
:bio, :location, :latitude, :longitude,
# email settings
:show_email, :newsletter, :send_notification_email, :send_planting_reminder
)
end
devise_parameter_sanitizer.for(:account_update) do |member|
member.permit(:login_name, :email, :password, :password_confirmation,
:remember_me, :login,
# terms of service
:tos_agreement,
# profile stuff
:bio, :location, :latitude, :longitude,
# email settings
:show_email, :newsletter, :send_notification_email, :send_planting_reminder,
#update password
:current_password
)
end
end
end

View File

@@ -1,15 +1,7 @@
class AuthenticationsController < ApplicationController
before_filter :authenticate_member!
load_and_authorize_resource
# GET /authentications
def index
@authentications = current_member.authentications if member_signed_in?
respond_to do |format|
format.html # index.html.erb
end
end
# POST /authentications
def create
auth = request.env['omniauth.auth']
@@ -26,12 +18,17 @@ class AuthenticationsController < ApplicationController
name = auth['info']['name']
end
@authentication = current_member.authentications.find_or_create_by_provider_and_uid(
:provider => auth['provider'],
:uid => auth['uid'],
@authentication = current_member.authentications
.create_with(
:name => name,
:token => auth['credentials']['token'],
:secret => auth['credentials']['secret'])
:secret => auth['credentials']['secret']
)
.find_or_create_by(
:provider => auth['provider'],
:uid => auth['uid'],
:name => name)
flash[:notice] = "Authentication successful."
else
flash[:notice] = "Authentication failed."

View File

@@ -1,8 +1,7 @@
class CommentsController < ApplicationController
before_filter :authenticate_member!, :except => [:index, :show]
load_and_authorize_resource
cache_sweeper :comment_sweeper
# GET /comments
# GET /comments.json
def index
@@ -54,11 +53,11 @@ class CommentsController < ApplicationController
# POST /comments.json
def create
params[:comment][:author_id] = current_member.id
@comment = Comment.new(params[:comment])
@comment = Comment.new(comment_params)
respond_to do |format|
if @comment.save
format.html { redirect_to @comment.post, notice: 'Comment was successfully created.' }
format.html { redirect_to @comment.post, notice: "Comment was successfully created." }
format.json { render json: @comment, status: :created, location: @comment }
else
format.html { render action: "new" }
@@ -78,7 +77,7 @@ class CommentsController < ApplicationController
params[:comment].delete("author_id")
respond_to do |format|
if @comment.update_attributes(params[:comment])
if @comment.update(comment_params)
format.html { redirect_to @comment.post, notice: 'Comment was successfully updated.' }
format.json { head :no_content }
else
@@ -100,4 +99,10 @@ class CommentsController < ApplicationController
format.json { head :no_content }
end
end
private
def comment_params
params.require(:comment).permit(:author_id, :body, :post_id)
end
end

View File

@@ -1,9 +1,8 @@
class CropsController < ApplicationController
before_filter :authenticate_member!, :except => [:index, :hierarchy, :search, :show]
load_and_authorize_resource
skip_authorize_resource :only => [:hierarchy, :search]
cache_sweeper :crop_sweeper
# GET /crops
# GET /crops.json
def index
@@ -55,7 +54,7 @@ class CropsController < ApplicationController
@partial_matches = Crop.search(params[:search])
# exclude exact match from partial match list
@partial_matches.reject!{ |r| @exact_match && r.eql?(@exact_match) }
@partial_matches = @partial_matches.reject{ |r| @exact_match && r.eql?(@exact_match) }
@fuzzy = Crop.search(params[:term])
@@ -103,7 +102,7 @@ class CropsController < ApplicationController
# POST /crops.json
def create
params[:crop][:creator_id] = current_member.id
@crop = Crop.new(params[:crop])
@crop = Crop.new(crop_params)
respond_to do |format|
if @crop.save
@@ -122,7 +121,7 @@ class CropsController < ApplicationController
@crop = Crop.find(params[:id])
respond_to do |format|
if @crop.update_attributes(params[:crop])
if @crop.update(crop_params)
format.html { redirect_to @crop, notice: 'Crop was successfully updated.' }
format.json { head :no_content }
else
@@ -143,4 +142,10 @@ class CropsController < ApplicationController
format.json { head :no_content }
end
end
private
def crop_params
params.require(:crop).permit(:en_wikipedia_url, :name, :parent_id, :creator_id, :scientific_names_attributes => [:scientific_name])
end
end

View File

@@ -0,0 +1,35 @@
class FollowsController < ApplicationController
before_filter :authenticate_member!
load_and_authorize_resource
skip_load_resource :only => :create
# POST /follows
def create
@follow = current_member.follows.build(:followed_id => follow_params[:followed_id])
if @follow.save
flash[:notice] = "Followed #{ @follow.followed.login_name }"
redirect_to :back
else
flash[:error] = "Already following or error while following."
redirect_to :back
end
end
# DELETE /follows/1
def destroy
@follow = current_member.follows.find(follow_params[:id])
unfollowed_name = @follow.followed.login_name
@follow.destroy
flash[:notice] = "Unfollowed #{ unfollowed_name }"
redirect_to root_path
end
private
def follow_params
params.permit(:id, :followed_id, :follower_id, :authenticity_token, :_method)
end
end

View File

@@ -1,8 +1,6 @@
class ForumsController < ApplicationController
load_and_authorize_resource
cache_sweeper :forum_sweeper
# GET /forums
# GET /forums.json
def index
@@ -44,7 +42,7 @@ class ForumsController < ApplicationController
# POST /forums
# POST /forums.json
def create
@forum = Forum.new(params[:forum])
@forum = Forum.new(forum_params)
respond_to do |format|
if @forum.save
@@ -63,7 +61,7 @@ class ForumsController < ApplicationController
@forum = Forum.find(params[:id])
respond_to do |format|
if @forum.update_attributes(params[:forum])
if @forum.update(forum_params)
format.html { redirect_to @forum, notice: 'Forum was successfully updated.' }
format.json { head :no_content }
else
@@ -84,4 +82,10 @@ class ForumsController < ApplicationController
format.json { head :no_content }
end
end
private
def forum_params
params.require(:forum).permit(:description, :name, :owner_id, :slug)
end
end

View File

@@ -1,7 +1,7 @@
class GardensController < ApplicationController
before_filter :authenticate_member!, :except => [:index, :show]
load_and_authorize_resource
cache_sweeper :garden_sweeper
# GET /gardens
# GET /gardens.json
@@ -49,12 +49,13 @@ class GardensController < ApplicationController
# POST /gardens.json
def create
params[:garden][:owner_id] = current_member.id
@garden = Garden.new(params[:garden])
@garden = Garden.new(garden_params)
respond_to do |format|
if @garden.save
format.html { redirect_to @garden, notice: 'Garden was successfully created.' }
format.json { render json: @garden, status: :created, location: @garden }
expire_fragment("homepage_stats")
else
format.html { render action: "new" }
format.json { render json: @garden.errors, status: :unprocessable_entity }
@@ -68,7 +69,7 @@ class GardensController < ApplicationController
@garden = Garden.find(params[:id])
respond_to do |format|
if @garden.update_attributes(params[:garden])
if @garden.update(garden_params)
format.html { redirect_to @garden, notice: 'Garden was successfully updated.' }
format.json { head :no_content }
else
@@ -83,10 +84,18 @@ class GardensController < ApplicationController
def destroy
@garden = Garden.find(params[:id])
@garden.destroy
expire_fragment("homepage_stats")
respond_to do |format|
format.html { redirect_to gardens_by_owner_path(:owner => @garden.owner), notice: 'Garden was successfully deleted.' }
format.json { head :no_content }
end
end
private
def garden_params
params.require(:garden).permit(:name, :slug, :owner_id, :description, :active,
:location, :latitude, :longitude, :area, :area_unit)
end
end

View File

@@ -1,6 +1,7 @@
class HarvestsController < ApplicationController
before_filter :authenticate_member!, :except => [:index, :show]
load_and_authorize_resource
# GET /harvests
# GET /harvests.json
@@ -61,7 +62,7 @@ class HarvestsController < ApplicationController
def create
params[:harvest][:owner_id] = current_member.id
params[:harvested_at] = parse_date(params[:harvested_at])
@harvest = Harvest.new(params[:harvest])
@harvest = Harvest.new(harvest_params)
respond_to do |format|
if @harvest.save
@@ -80,7 +81,7 @@ class HarvestsController < ApplicationController
@harvest = Harvest.find(params[:id])
respond_to do |format|
if @harvest.update_attributes(params[:harvest])
if @harvest.update(harvest_params)
format.html { redirect_to @harvest, notice: 'Harvest was successfully updated.' }
format.json { head :no_content }
else
@@ -101,4 +102,11 @@ class HarvestsController < ApplicationController
format.json { head :no_content }
end
end
private
def harvest_params
params.require(:harvest).permit(:crop_id, :harvested_at, :description, :owner_id,
:quantity, :unit, :weight_quantity, :weight_unit, :plant_part_id, :slug)
end
end

View File

@@ -1,10 +1,10 @@
class MembersController < ApplicationController
load_and_authorize_resource
cache_sweeper :member_sweeper
skip_authorize_resource :only => :nearby
after_action :expire_cache_fragments, :only => :create
def index
@members = Member.confirmed.paginate(:page => params[:page])
@@ -23,7 +23,7 @@ class MembersController < ApplicationController
# it requires a garden to be passed in @garden.
# The new garden is not persisted unless Garden#save is called.
@garden = Garden.new
respond_to do |format|
format.html # show.html.haml
format.json { render :json => @member.to_json(:only => [:id, :login_name, :bio, :created_at, :slug, :location, :latitude, :longitude]) }
@@ -34,4 +34,20 @@ class MembersController < ApplicationController
end
end
def view_follows
@member = Member.confirmed.find(params[:login_name])
@follows = @member.followed.paginate(:page => params[:page])
end
def view_followers
@member = Member.confirmed.find(params[:login_name])
@followers = @member.followers.paginate(:page => params[:page])
end
private
def expire_cache_fragments
expire_fragment("homepage_stats")
end
end

View File

@@ -1,9 +1,11 @@
class NotificationsController < ApplicationController
include NotificationsHelper
before_filter :authenticate_member!
load_and_authorize_resource
# GET /notifications
def index
@notifications = Notification.find_all_by_recipient_id(current_member)
@notifications = Notification.where(recipient_id: current_member)
respond_to do |format|
format.html # index.html.erb
@@ -47,7 +49,7 @@ class NotificationsController < ApplicationController
# POST /notifications
def create
params[:notification][:sender_id] = current_member.id
@notification = Notification.new(params[:notification])
@notification = Notification.new(notification_params)
@recipient = Member.find_by_id(params[:notification][:recipient_id])
respond_to do |format|
@@ -58,4 +60,10 @@ class NotificationsController < ApplicationController
end
end
end
private
def notification_params
params.require(:notification).permit(:sender_id, :recipient_id, :subject, :body, :post_id, :read)
end
end

View File

@@ -1,4 +1,5 @@
class OrderItemsController < ApplicationController
before_filter :authenticate_member!
load_and_authorize_resource
# POST /order_items
@@ -6,7 +7,7 @@ class OrderItemsController < ApplicationController
if params[:order_item][:price]
params[:order_item][:price] = params[:order_item][:price].to_f * 100 # convert to cents
end
@order_item = OrderItem.new(params[:order_item])
@order_item = OrderItem.new(order_item_params)
@order_item.order = current_member.current_order || Order.create(:member_id => current_member.id)
respond_to do |format|
@@ -19,4 +20,10 @@ class OrderItemsController < ApplicationController
end
end
end
private
def order_item_params
params.require(:order_item).permit(:order_id, :price, :product_id, :quantity)
end
end

View File

@@ -1,9 +1,10 @@
class OrdersController < ApplicationController
before_filter :authenticate_member!
load_and_authorize_resource
# GET /orders
def index
@orders = Order.find_all_by_member_id(current_member.id)
@orders = Order.where(member_id: current_member.id)
respond_to do |format|
format.html # index.html.erb

View File

@@ -1,8 +1,7 @@
class PhotosController < ApplicationController
before_filter :authenticate_member!, :except => [:index, :show]
load_and_authorize_resource
cache_sweeper :photo_sweeper
# GET /photos
# GET /photos.json
def index
@@ -60,7 +59,7 @@ class PhotosController < ApplicationController
# POST /photos.json
def create
@photo = Photo.find_by_flickr_photo_id(params[:photo][:flickr_photo_id]) ||
Photo.new(params[:photo])
Photo.new(photo_params)
@photo.owner_id = current_member.id
@photo.set_flickr_metadata
@@ -110,7 +109,7 @@ class PhotosController < ApplicationController
@photo = Photo.find(params[:id])
respond_to do |format|
if @photo.update_attributes(params[:photo])
if @photo.update(photo_params)
format.html { redirect_to @photo, notice: 'Photo was successfully updated.' }
format.json { head :no_content }
else
@@ -131,4 +130,11 @@ class PhotosController < ApplicationController
format.json { head :no_content }
end
end
private
def photo_params
params.require(:photo).permit(:flickr_photo_id, :owner_id, :title, :license_name,
:license_url, :thumbnail_url, :fullsize_url, :link_url)
end
end

View File

@@ -42,7 +42,7 @@ class PlantPartsController < ApplicationController
# POST /plant_parts
# POST /plant_parts.json
def create
@plant_part = PlantPart.new(params[:plant_part])
@plant_part = PlantPart.new(plant_part_params)
respond_to do |format|
if @plant_part.save
@@ -61,7 +61,7 @@ class PlantPartsController < ApplicationController
@plant_part = PlantPart.find(params[:id])
respond_to do |format|
if @plant_part.update_attributes(params[:plant_part])
if @plant_part.update(plant_part_params)
format.html { redirect_to @plant_part, notice: 'Plant part was successfully updated.' }
format.json { head :no_content }
else
@@ -82,4 +82,10 @@ class PlantPartsController < ApplicationController
format.json { head :no_content }
end
end
private
def plant_part_params
params.require(:plant_part).permit(:name, :slug)
end
end

View File

@@ -1,8 +1,7 @@
class PlantingsController < ApplicationController
before_filter :authenticate_member!, :except => [:index, :show]
load_and_authorize_resource
cache_sweeper :planting_sweeper
# GET /plantings
# GET /plantings.json
def index
@@ -31,7 +30,7 @@ class PlantingsController < ApplicationController
# GET /plantings/1
# GET /plantings/1.json
def show
@planting = Planting.includes(:owner, :crop, :garden, :photos).find(params[:id])
@planting = Planting.includes(:owner, :crop, :garden, :photos).friendly.find(params[:id])
respond_to do |format|
format.html # show.html.erb
@@ -66,14 +65,15 @@ class PlantingsController < ApplicationController
# POST /plantings
# POST /plantings.json
def create
params[:planting][:owner_id] = current_member.id
params[:planted_at] = parse_date(params[:planted_at])
@planting = Planting.new(params[:planting])
@planting = Planting.new(planting_params)
@planting.owner = current_member
respond_to do |format|
if @planting.save
format.html { redirect_to @planting, notice: 'Planting was successfully created.' }
format.json { render json: @planting, status: :created, location: @planting }
expire_fragment("homepage_stats")
else
format.html { render action: "new" }
format.json { render json: @planting.errors, status: :unprocessable_entity }
@@ -88,7 +88,7 @@ class PlantingsController < ApplicationController
params[:planted_at] = parse_date(params[:planted_at])
respond_to do |format|
if @planting.update_attributes(params[:planting])
if @planting.update(planting_params)
format.html { redirect_to @planting, notice: 'Planting was successfully updated.' }
format.json { head :no_content }
else
@@ -104,10 +104,19 @@ class PlantingsController < ApplicationController
@planting = Planting.find(params[:id])
@garden = @planting.garden
@planting.destroy
expire_fragment("homepage_stats")
respond_to do |format|
format.html { redirect_to @garden }
format.json { head :no_content }
end
end
private
def planting_params
params.require(:planting).permit(:crop_id, :description, :garden_id, :planted_at,
:quantity, :sunniness, :planted_from, :owner_id, :finished,
:finished_at)
end
end

View File

@@ -1,8 +1,7 @@
class PostsController < ApplicationController
before_filter :authenticate_member!, :except => [:index, :show]
load_and_authorize_resource
cache_sweeper :post_sweeper
# GET /posts
# GET /posts.json
@@ -57,7 +56,7 @@ class PostsController < ApplicationController
# POST /posts.json
def create
params[:post][:author_id] = current_member.id
@post = Post.new(params[:post])
@post = Post.new(post_params)
respond_to do |format|
if @post.save
@@ -76,7 +75,7 @@ class PostsController < ApplicationController
@post = Post.find(params[:id])
respond_to do |format|
if @post.update_attributes(params[:post])
if @post.update(post_params)
format.html { redirect_to @post, notice: 'Post was successfully updated.' }
format.json { head :no_content }
else
@@ -97,4 +96,10 @@ class PostsController < ApplicationController
format.json { head :no_content }
end
end
private
def post_params
params.require(:post).permit(:body, :subject, :author_id, :forum_id)
end
end

View File

@@ -1,5 +1,7 @@
class ProductsController < ApplicationController
before_filter :authenticate_member!
load_and_authorize_resource
# GET /products
def index
@products = Product.all
@@ -34,7 +36,7 @@ class ProductsController < ApplicationController
# POST /products
def create
@product = Product.new(params[:product])
@product = Product.new(product_params)
respond_to do |format|
if @product.save
@@ -50,7 +52,7 @@ class ProductsController < ApplicationController
@product = Product.find(params[:id])
respond_to do |format|
if @product.update_attributes(params[:product])
if @product.update(product_params)
format.html { redirect_to @product, notice: 'Product was successfully updated.' }
else
format.html { render action: "edit" }
@@ -67,4 +69,11 @@ class ProductsController < ApplicationController
format.html { redirect_to products_url }
end
end
private
def product_params
params.require(:product).permit(:description, :min_price, :recommended_price, :name,
:account_type_id, :paid_months)
end
end

View File

@@ -1,7 +1,5 @@
class RegistrationsController < Devise::RegistrationsController
cache_sweeper :member_sweeper
def edit
@twitter_auth = current_member.auth('twitter')
@flickr_auth = current_member.auth('flickr')

View File

@@ -1,5 +1,7 @@
class RolesController < ApplicationController
before_filter :authenticate_member!
load_and_authorize_resource
# GET /roles
def index
@roles = Role.all
@@ -34,7 +36,7 @@ class RolesController < ApplicationController
# POST /roles
def create
@role = Role.new(params[:role])
@role = Role.new(role_params)
respond_to do |format|
if @role.save
@@ -50,7 +52,7 @@ class RolesController < ApplicationController
@role = Role.find(params[:id])
respond_to do |format|
if @role.update_attributes(params[:role])
if @role.update(role_params)
format.html { redirect_to @role, notice: 'Role was successfully updated.' }
else
format.html { render action: "edit" }
@@ -67,4 +69,10 @@ class RolesController < ApplicationController
format.html { redirect_to roles_url }
end
end
private
def role_params
params.require(:role).permit(:description, :name, :members, :slug)
end
end

View File

@@ -1,8 +1,7 @@
class ScientificNamesController < ApplicationController
before_filter :authenticate_member!, :except => [:index, :show]
load_and_authorize_resource
cache_sweeper :scientific_name_sweeper
# GET /scientific_names
# GET /scientific_names.json
def index
@@ -46,7 +45,7 @@ class ScientificNamesController < ApplicationController
# POST /scientific_names.json
def create
params[:scientific_name][:creator_id] = current_member.id
@scientific_name = ScientificName.new(params[:scientific_name])
@scientific_name = ScientificName.new(scientific_name_params)
respond_to do |format|
if @scientific_name.save
@@ -65,7 +64,7 @@ class ScientificNamesController < ApplicationController
@scientific_name = ScientificName.find(params[:id])
respond_to do |format|
if @scientific_name.update_attributes(params[:scientific_name])
if @scientific_name.update(scientific_name_params)
format.html { redirect_to @scientific_name.crop, notice: 'Scientific name was successfully updated.' }
format.json { head :no_content }
else
@@ -89,4 +88,10 @@ class ScientificNamesController < ApplicationController
format.json { head :no_content }
end
end
private
def scientific_name_params
params.require(:scientific_name).permit(:crop_id, :scientific_name, :creator_id)
end
end

View File

@@ -1,8 +1,7 @@
class SeedsController < ApplicationController
before_filter :authenticate_member!, :except => [:index, :show]
load_and_authorize_resource
cache_sweeper :seed_sweeper
# GET /seeds
# GET /seeds.json
def index
@@ -67,7 +66,7 @@ class SeedsController < ApplicationController
# POST /seeds.json
def create
params[:seed][:owner_id] = current_member.id
@seed = Seed.new(params[:seed])
@seed = Seed.new(seed_params)
respond_to do |format|
if @seed.save
@@ -86,7 +85,7 @@ class SeedsController < ApplicationController
@seed = Seed.find(params[:id])
respond_to do |format|
if @seed.update_attributes(params[:seed])
if @seed.update(seed_params)
format.html { redirect_to @seed, notice: 'Seed was successfully updated.' }
format.json { head :no_content }
else
@@ -107,4 +106,11 @@ class SeedsController < ApplicationController
format.json { head :no_content }
end
end
private
def seed_params
params.require(:seed).permit(:owner_id, :crop_id, :description, :quantity, :plant_before,
:tradable_to, :slug)
end
end

View File

@@ -24,5 +24,12 @@ module ApplicationHelper
:target => "_blank"
end
# Produces a cache key for uniquely identifying cached fragments.
def cache_key_for(klass, identifier="all")
count = klass.count
max_updated_at = klass.maximum(:updated_at).try(:utc).try(:to_s, :number)
"#{klass.name.downcase.pluralize}/#{identifier}-#{count}-#{max_updated_at}"
end
end

View File

@@ -13,8 +13,8 @@ class Notifier < ActionMailer::Base
def planting_reminder(member)
@member = member
@plantings = @member.plantings.reorder.last(5)
@harvests = @member.harvests.reorder.last(5)
@plantings = @member.plantings.first(5)
@harvests = @member.harvests.first(5)
if @member.send_planting_reminder
mail(:to => @member.email,

View File

@@ -6,6 +6,8 @@ class Ability
# everyone can do these things, even non-logged in
can :read, :all
can :view_follows, Member
can :view_followers, Member
# except these, which don't make sense if you're not logged in
cannot :read, Notification
@@ -91,6 +93,13 @@ class Ability
cannot :update, OrderItem, :order => { :member_id => member.id, :completed_at => nil }
cannot :destroy, OrderItem, :order => { :member_id => member.id, :completed_at => nil }
# following/unfollowing permissions
can :create, Follow
cannot :create, Follow, :followed_id => member.id # can't follow yourself
can :destroy, Follow
cannot :destroy, Follow, :followed_id => member.id # can't unfollow yourself
if member.has_role? :admin
can :read, :all

View File

@@ -1,5 +1,4 @@
class Account < ActiveRecord::Base
attr_accessible :account_type_id, :member_id, :paid_until
belongs_to :member
belongs_to :account_type
@@ -9,7 +8,7 @@ class Account < ActiveRecord::Base
before_create do |account|
unless account.account_type
account.account_type = AccountType.find_or_create_by_name(
account.account_type = AccountType.find_or_create_by(name:
Growstuff::Application.config.default_account_type
)
end

View File

@@ -1,5 +1,4 @@
class AccountType < ActiveRecord::Base
attr_accessible :is_paid, :is_permanent_paid, :name
has_many :products
def to_s

View File

@@ -1,5 +1,4 @@
class AlternateName < ActiveRecord::Base
attr_accessible :crop_id, :name, :creator_id
belongs_to :crop
belongs_to :creator, :class_name => 'Member'
end

View File

@@ -1,4 +1,3 @@
class Authentication < ActiveRecord::Base
belongs_to :member
attr_accessible :provider, :uid, :token, :secret, :name
end

View File

@@ -1,10 +1,9 @@
class Comment < ActiveRecord::Base
attr_accessible :author_id, :body, :post_id
belongs_to :author, :class_name => 'Member'
belongs_to :post
default_scope order("created_at DESC")
scope :post_order, reorder("created_at ASC") # for display on post page
default_scope { order("created_at DESC") }
scope :post_order, -> { reorder("created_at ASC") } # for display on post page
after_create do
recipient = self.post.author.id

View File

@@ -1,15 +0,0 @@
class CommentSweeper < ActionController::Caching::Sweeper
observe Comment
def after_create(comment)
expire_fragment('recent_posts')
end
def after_update(comment)
end
def after_destroy(comment)
expire_fragment('recent_posts')
end
end

View File

@@ -1,7 +1,6 @@
class Crop < ActiveRecord::Base
extend FriendlyId
friendly_id :name, use: :slugged
attr_accessible :en_wikipedia_url, :name, :parent_id, :creator_id, :scientific_names_attributes
friendly_id :name, use: [:slugged, :finders]
has_many :scientific_names
accepts_nested_attributes_for :scientific_names,
@@ -13,7 +12,7 @@ class Crop < ActiveRecord::Base
has_many :photos, :through => :plantings
has_many :seeds
has_many :harvests
has_many :plant_parts, :through => :harvests, :uniq => :true
has_many :plant_parts, -> { uniq }, :through => :harvests
belongs_to :creator, :class_name => 'Member'
belongs_to :parent, :class_name => 'Crop'
@@ -21,16 +20,15 @@ class Crop < ActiveRecord::Base
has_and_belongs_to_many :posts
before_destroy {|crop| crop.posts.clear}
default_scope order("lower(name) asc")
scope :recent, reorder("created_at desc")
scope :toplevel, where(:parent_id => nil)
scope :popular, reorder("plantings_count desc, lower(name) asc")
scope :randomized, reorder('random()') # ok on sqlite and psql, but not on mysql
default_scope { order("lower(name) asc") }
scope :recent, -> { reorder("created_at desc") }
scope :toplevel, -> { where(:parent_id => nil) }
scope :popular, -> { reorder("plantings_count desc, lower(name) asc") }
scope :randomized, -> { reorder('random()') } # ok on sqlite and psql, but not on mysql
validates :en_wikipedia_url,
:format => {
:with => /^https?:\/\/en\.wikipedia\.org\/wiki/,
:with => /\Ahttps?:\/\/en\.wikipedia\.org\/wiki/,
:message => 'is not a valid English Wikipedia URL'
}
@@ -122,17 +120,17 @@ class Crop < ActiveRecord::Base
# used by db/seeds.rb and rake growstuff:import_crops
# CSV fields:
# - name (required)
# - scientific name (optional, can be picked up from parent if it has one)
# - en_wikipedia_url (required)
# - parent (name, optional)
# - scientific name (optional, can be picked up from parent if it has one)
def Crop.create_from_csv(row)
name,scientific_name,en_wikipedia_url,parent = row
name,en_wikipedia_url,parent,scientific_names,alternate_names = row
cropbot = Member.find_by_login_name('cropbot')
raise "cropbot account not found: run rake db:seed" unless cropbot
crop = Crop.find_or_create_by_name(name)
crop = Crop.find_or_create_by(name: name)
crop.update_attributes(
:en_wikipedia_url => en_wikipedia_url,
:creator_id => cropbot.id
@@ -147,34 +145,59 @@ class Crop < ActiveRecord::Base
end
end
crop.add_scientific_name_from_csv(scientific_name)
crop.add_scientific_names_from_csv(scientific_names)
crop.add_alternate_names_from_csv(alternate_names)
end
def add_scientific_name_from_csv(scientific_name)
name_to_add = nil
if ! scientific_name.blank? # i.e. we actually passed one in, which isn't a given
name_to_add = scientific_name
elsif parent && parent.default_scientific_name
name_to_add = parent.default_scientific_name
def add_scientific_names_from_csv(scientific_names)
names_to_add = []
if ! scientific_names.blank? # i.e. we actually passed something in, which isn't a given
names_to_add = scientific_names.split(%r{,\s*})
elsif parent && parent.scientific_names.size > 0 # pick up from parent
names_to_add = parent.scientific_names.map{|s| s.scientific_name}
else
logger.warn("Warning: no scientific name (not even on parent crop) for #{self}")
end
if name_to_add
if scientific_names.exists?(:scientific_name => name_to_add)
logger.warn("Warning: skipping duplicate scientific name #{name_to_add} for #{self}")
else
cropbot = Member.find_by_login_name('cropbot')
raise "cropbot account not found: run rake db:seed" unless cropbot
if names_to_add.size > 0
cropbot = Member.find_by_login_name('cropbot')
raise "cropbot account not found: run rake db:seed" unless cropbot
scientific_names.create(
:scientific_name => name_to_add,
:creator_id => cropbot.id
)
names_to_add.each do |n|
if self.scientific_names.exists?(:scientific_name => n)
logger.warn("Warning: skipping duplicate scientific name #{n} for #{self}")
else
self.scientific_names.create(
:scientific_name => n,
:creator_id => cropbot.id
)
end
end
end
end
def add_alternate_names_from_csv(alternate_names)
names_to_add = []
if ! alternate_names.blank? # i.e. we actually passed something in, which isn't a given
cropbot = Member.find_by_login_name('cropbot')
raise "cropbot account not found: run rake db:seed" unless cropbot
names_to_add = alternate_names.split(%r{,\s*})
names_to_add.each do |n|
if self.alternate_names.exists?(:name => n)
logger.warn("Warning: skipping duplicate alternate name #{n} for #{self}")
else
self.alternate_names.create(
:name => n,
:creator_id => cropbot.id
)
end
end
end
end
# Crop.search(string)

View File

@@ -1,21 +0,0 @@
class CropSweeper < ActionController::Caching::Sweeper
observe Crop
def after_create(crop)
expire_fragment('homepage_stats')
expire_fragment('recent_crops')
expire_fragment('full_crop_hierarchy')
end
def after_update(crop)
expire_fragment("crop_image_#{crop.id}")
end
def after_destroy(crop)
expire_fragment('homepage_stats')
expire_fragment('recent_crops')
expire_fragment('full_crop_hierarchy')
end
end

16
app/models/follow.rb Normal file
View File

@@ -0,0 +1,16 @@
class Follow < ActiveRecord::Base
belongs_to :follower, class_name: "Member"
belongs_to :followed, class_name: "Member"
validates :follower_id, uniqueness: { :scope => :followed_id }
after_create do
Notification.create(
:recipient_id => self.followed_id,
:sender_id => self.follower_id,
:subject => "#{self.follower.login_name} is now following you",
:body => "#{self.follower.login_name} just followed you on #{ENV["GROWSTUFF_SITE_NAME"]}. "
)
end
end

View File

@@ -1,7 +1,7 @@
class Forum < ActiveRecord::Base
extend FriendlyId
friendly_id :name, use: :slugged
attr_accessible :description, :name, :owner_id, :slug
friendly_id :name, use: [:slugged, :finders]
has_many :posts
belongs_to :owner, :class_name => "Member"

View File

@@ -1,16 +0,0 @@
class ForumSweeper < ActionController::Caching::Sweeper
observe Forum
def after_create(forum)
expire_fragment('homepage_forums')
end
def after_update(forum)
expire_fragment('homepage_forums')
end
def after_destroy(forum)
expire_fragment('homepage_forums')
end
end

View File

@@ -1,13 +1,10 @@
class Garden < ActiveRecord::Base
include Geocodable
extend FriendlyId
friendly_id :garden_slug, use: :slugged
attr_accessible :name, :slug, :owner_id, :description, :active,
:location, :latitude, :longitude, :area, :area_unit
friendly_id :garden_slug, use: [:slugged, :finders]
belongs_to :owner, :class_name => 'Member', :foreign_key => 'owner_id'
has_many :plantings, :order => 'created_at DESC', :dependent => :destroy
has_many :plantings, -> { order(created_at: :desc) }, :dependent => :destroy
has_many :crops, :through => :plantings
# set up geocoding
@@ -16,9 +13,9 @@ class Garden < ActiveRecord::Base
after_validation :empty_unwanted_geocodes
after_save :mark_inactive_garden_plantings_as_finished
default_scope order("lower(name) asc")
scope :active, where(:active => true)
scope :inactive, where(:active => false)
default_scope { order("lower(name) asc") }
scope :active, -> { where(:active => true) }
scope :inactive, -> { where(:active => false) }
validates :name,
:format => {

View File

@@ -1,16 +0,0 @@
class GardenSweeper < ActionController::Caching::Sweeper
observe Garden
def after_create(garden)
expire_fragment('homepage_stats')
expire_fragment('interesting_members') if garden.owner.interesting?
expire_fragment("member_thumbnail_#{garden.owner.id}")
end
def after_destroy(garden)
expire_fragment('homepage_stats')
expire_fragment('interesting_members') if garden.owner.interesting?
expire_fragment("member_thumbnail_#{garden.owner.id}")
end
end

View File

@@ -1,10 +1,7 @@
class Harvest < ActiveRecord::Base
include ActionView::Helpers::NumberHelper
extend FriendlyId
friendly_id :harvest_slug, use: :slugged
attr_accessible :crop_id, :harvested_at, :description, :owner_id,
:quantity, :unit, :weight_quantity, :weight_unit, :plant_part_id, :slug, :si_weight
friendly_id :harvest_slug, use: [:slugged, :finders]
belongs_to :crop
belongs_to :owner, :class_name => 'Member'
@@ -21,7 +18,7 @@ class Harvest < ActiveRecord::Base
end
end
default_scope order('created_at DESC')
default_scope { order('created_at DESC') }
validates :crop, :presence => {:message => "must be present and exist in our database"}

View File

@@ -2,7 +2,7 @@ class Member < ActiveRecord::Base
include Geocodable
extend FriendlyId
friendly_id :login_name, use: :slugged
friendly_id :login_name, use: [:slugged, :finders]
has_many :posts, :foreign_key => 'author_id'
has_many :comments, :foreign_key => 'author_id'
@@ -27,11 +27,18 @@ class Member < ActiveRecord::Base
has_many :photos
default_scope order("lower(login_name) asc")
scope :confirmed, where('confirmed_at IS NOT NULL')
scope :located, where("location <> '' and latitude IS NOT NULL and longitude IS NOT NULL")
scope :recently_signed_in, reorder('updated_at DESC')
scope :wants_newsletter, where(:newsletter => true)
default_scope { order("lower(login_name) asc") }
scope :confirmed, -> { where('confirmed_at IS NOT NULL') }
scope :located, -> { where("location <> '' and latitude IS NOT NULL and longitude IS NOT NULL") }
scope :recently_signed_in, -> { reorder('updated_at DESC') }
scope :wants_newsletter, -> { where(:newsletter => true) }
has_many :follows, :class_name => "Follow", :foreign_key => "follower_id"
has_many :followed, :through => :follows
has_many :inverse_follows, :class_name => "Follow", :foreign_key => "followed_id"
has_many :followers, :through => :inverse_follows, :source => :follower
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
@@ -40,16 +47,6 @@ class Member < ActiveRecord::Base
:recoverable, :rememberable, :trackable, :validatable,
:confirmable, :lockable, :timeoutable
# Setup accessible (or protected) attributes for your model
attr_accessible :login_name, :email, :password, :password_confirmation,
:remember_me, :login,
# terms of service
:tos_agreement,
# profile stuff
:bio, :location, :latitude, :longitude,
# email settings
:show_email, :newsletter, :send_notification_email, :send_planting_reminder
# set up geocoding
geocoded_by :location
after_validation :geocode
@@ -74,7 +71,7 @@ class Member < ActiveRecord::Base
:message => "name is reserved"
},
:format => {
:with => /^\w+$/,
:with => /\A\w+\z/,
:message => "may only include letters, numbers, or underscores"
},
:uniqueness => {
@@ -87,7 +84,7 @@ class Member < ActiveRecord::Base
# and an account record (for paid accounts etc)
# we use find_or_create to avoid accidentally creating a second one,
# which can happen sometimes especially with FactoryGirl associations
after_create {|member| Account.find_or_create_by_member_id(:member_id => member.id) }
after_create {|member| Account.find_or_create_by(:member_id => member.id) }
after_save :update_newsletter_subscription
@@ -237,17 +234,19 @@ class Member < ActiveRecord::Base
end
end
def newsletter_subscribe
def newsletter_subscribe(testing=false)
return true if (Rails.env.test? && !testing)
gb = Gibbon::API.new
res = gb.lists.subscribe({
:id => Gibbon::API.api_key,
:email => { :email => email },
:merge_vars => { :login_name => login_name },
:double_optin => false # they alredy confirmed their email with us
:double_optin => false # they already confirmed their email with us
})
end
def newsletter_unsubscribe
def newsletter_unsubscribe(testing=false)
return true if (Rails.env.test? && !testing)
gb = Gibbon::API.new
res = gb.lists.unsubscribe({
:id => ENV['GROWSTUFF_MAILCHIMP_NEWSLETTER_ID'],
@@ -255,4 +254,12 @@ class Member < ActiveRecord::Base
})
end
def already_following?(member)
self.follows.exists?(:followed_id => member.id)
end
def get_follow(member)
self.follows.where(:followed_id => member.id).first if already_following?(member)
end
end

View File

@@ -1,23 +0,0 @@
class MemberSweeper < ActionController::Caching::Sweeper
observe Member
def after_create(member)
expire_fragment('homepage_stats')
end
def after_update(member)
expire_fragment('interesting_members') if member.interesting?
expire_fragment("interesting_seeds") if member.seeds.tradable.present?
expire_fragment("member_thumbnail_#{member.id}")
if member.plantings.present?
member.plantings.each do |p|
expire_fragment("plantings_listitem_#{p.id}") if p.interesting?
end
expire_fragment('interesting_plantings')
end
end
end

View File

@@ -1,13 +1,10 @@
class Notification < ActiveRecord::Base
attr_accessible :sender_id, :recipient_id,
:subject, :body, :post_id, :read
belongs_to :sender, :class_name => 'Member'
belongs_to :recipient, :class_name => 'Member'
belongs_to :post
default_scope order('created_at DESC')
scope :unread, where(:read => false)
default_scope { order('created_at DESC') }
scope :unread, -> { where(:read => false) }
before_create :replace_blank_subject
after_create :send_email

View File

@@ -1,10 +1,9 @@
class Order < ActiveRecord::Base
attr_accessible :member_id, :completed_at, :referral_code
belongs_to :member
has_many :order_items, :dependent => :destroy
default_scope order('created_at DESC')
default_scope { order('created_at DESC') }
validates :referral_code, :format => {
:with => /\A[a-zA-Z0-9 ]*\z/,

View File

@@ -1,6 +1,4 @@
class OrderItem < ActiveRecord::Base
attr_accessible :order_id, :price, :product_id, :quantity
belongs_to :order
belongs_to :product

View File

@@ -1,6 +1,4 @@
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
@@ -10,7 +8,7 @@ class Photo < ActiveRecord::Base
photo.harvests.clear
end
default_scope order("created_at desc")
default_scope { order("created_at desc") }
# remove photos that aren't used by anything
def destroy_if_unused

View File

@@ -1,13 +0,0 @@
class PhotoSweeper < ActionController::Caching::Sweeper
observe Photo
def after_create(photo)
expire_fragment('interesting_plantings')
end
def after_destroy(photo)
expire_fragment('interesting_plantings')
end
end

View File

@@ -1,11 +1,9 @@
class PlantPart < ActiveRecord::Base
extend FriendlyId
friendly_id :name, :use => :slugged
friendly_id :name, :use => [:slugged, :finders]
has_many :harvests
has_many :crops, :through => :harvests, :uniq => true
attr_accessible :name, :slug
has_many :crops, -> { uniq }, :through => :harvests
def to_s
return name

View File

@@ -1,10 +1,6 @@
class Planting < ActiveRecord::Base
extend FriendlyId
friendly_id :planting_slug, use: :slugged
attr_accessible :crop_id, :description, :garden_id, :planted_at,
:quantity, :sunniness, :planted_from, :owner_id, :finished,
:finished_at
friendly_id :planting_slug, use: [:slugged, :finders]
belongs_to :garden
belongs_to :owner, :class_name => 'Member', :counter_cache => true
@@ -21,9 +17,9 @@ class Planting < ActiveRecord::Base
end
end
default_scope order("created_at desc")
scope :finished, where(:finished => true)
scope :current, where(:finished => false)
default_scope { order("created_at desc") }
scope :finished, -> { where(:finished => true) }
scope :current, -> { where(:finished => false) }
delegate :name,
:en_wikipedia_url,
@@ -32,7 +28,7 @@ class Planting < ActiveRecord::Base
:to => :crop,
:prefix => true
default_scope order("created_at desc")
default_scope { order("created_at desc") }
validates :crop_id, :presence => {:message => "must be present and exist in our database"}

View File

@@ -1,25 +0,0 @@
class PlantingSweeper < ActionController::Caching::Sweeper
observe Planting
def after_create(planting)
expire_fragment('homepage_stats')
expire_fragment("member_thumbnail_#{planting.owner.id}")
expire_fragment("interesting_members") if planting.owner.interesting?
expire_fragment("crop_image_#{planting.crop.id}")
end
def after_update(planting)
expire_fragment("planting_listitem_#{planting.id}")
expire_fragment("planting_image_#{planting.id}")
expire_fragment("interesting_plantings")
end
def after_destroy(planting)
expire_fragment('homepage_stats')
expire_fragment("crop_image_#{planting.crop.id}")
expire_fragment('interesting_plantings') if planting.interesting?
expire_fragment("interesting_members") if planting.owner.interesting?
end
end

View File

@@ -1,7 +1,6 @@
class Post < ActiveRecord::Base
extend FriendlyId
friendly_id :author_date_subject, use: :slugged
attr_accessible :body, :subject, :author_id, :forum_id
friendly_id :author_date_subject, use: [:slugged, :finders]
belongs_to :author, :class_name => 'Member'
belongs_to :forum
has_many :comments, :dependent => :destroy
@@ -11,7 +10,7 @@ class Post < ActiveRecord::Base
# also has_many notifications, but kinda meaningless to get at them
# from this direction, so we won't set up an association for now.
default_scope order("created_at desc")
default_scope { order("created_at desc") }
validates :subject,
:format => {

View File

@@ -1,16 +0,0 @@
class PostSweeper < ActionController::Caching::Sweeper
observe Post
def after_create(post)
expire_fragment('recent_posts')
end
def after_update(post)
expire_fragment('recent_posts')
end
def after_destroy(post)
expire_fragment('recent_posts')
end
end

View File

@@ -1,7 +1,4 @@
class Product < ActiveRecord::Base
attr_accessible :description, :min_price, :recommended_price, :name,
:account_type_id, :paid_months
has_and_belongs_to_many :orders
belongs_to :account_type

View File

@@ -1,7 +1,7 @@
class Role < ActiveRecord::Base
extend FriendlyId
friendly_id :name, use: :slugged
attr_accessible :description, :name, :members, :slug
friendly_id :name, use: [:slugged, :finders]
has_and_belongs_to_many :members
class << self

View File

@@ -1,5 +1,4 @@
class ScientificName < ActiveRecord::Base
attr_accessible :crop_id, :scientific_name, :creator_id
belongs_to :crop
belongs_to :creator, :class_name => 'Member'
end

View File

@@ -1,17 +0,0 @@
class ScientificNameSweeper < ActionController::Caching::Sweeper
observe ScientificName
def after_create(scientific_name)
expire_fragment("crop_image_#{scientific_name.crop.id}")
end
def after_update(scientific_name)
expire_fragment("crop_image_#{scientific_name.crop.id}")
end
def after_destroy(scientific_name)
expire_fragment("crop_image_#{scientific_name.crop.id}")
end
end

View File

@@ -1,21 +1,18 @@
class Seed < ActiveRecord::Base
extend FriendlyId
friendly_id :seed_slug, use: :slugged
attr_accessible :owner_id, :crop_id, :description, :quantity, :plant_before,
:tradable_to, :slug
friendly_id :seed_slug, use: [:slugged, :finders]
belongs_to :crop
belongs_to :owner, :class_name => 'Member', :foreign_key => 'owner_id'
default_scope order("created_at desc")
default_scope { order("created_at desc") }
validates :crop, :presence => {:message => "must be present and exist in our database"}
validates :quantity,
:numericality => { :only_integer => true },
:allow_nil => true
scope :tradable, where("tradable_to != 'nowhere'")
scope :tradable, -> { where("tradable_to != 'nowhere'") }
TRADABLE_TO_VALUES = %w(nowhere locally nationally internationally)
validates :tradable_to, :inclusion => { :in => TRADABLE_TO_VALUES,

View File

@@ -1,26 +0,0 @@
class SeedSweeper < ActionController::Caching::Sweeper
observe Seed
def after_create(seed)
if seed.tradable? && seed.interesting?
expire_fragment('interesting_seeds')
end
expire_fragment('interesting_members') if seed.owner.interesting?
expire_fragment("member_thumbnail_#{seed.owner.id}")
end
def after_update(seed)
expire_fragment('interesting_seeds')
end
def after_destroy(seed)
if seed.tradable? && seed.interesting?
expire_fragment('interesting_seeds')
end
expire_fragment('interesting_members') if seed.owner.interesting?
expire_fragment("member_thumbnail_#{seed.owner.id}")
end
end

View File

@@ -1,22 +0,0 @@
- content_for :title, "Linked accounts on other sites"
- if @authentications
- unless @authentications.empty?
.authentications
- @authentications.each do |authentication|
%a{ :href => "http://twitter.com/#{authentication.name}" }
.authentication
= image_tag "#{authentication.provider}_64.png", :size => "64x64"
.provider
= authentication.provider.titleize
.name
= authentication.name
= link_to "X", authentication, :confirm => "Are you sure you want to remove this authentication?", :method => :delete, :class => "remove"
.clear
%p
%strong Link another external account:
- else
%p
%strong Link to an external account:
= link_to image_tag("twitter_64.png", :size => "64x64"), "/auth/twitter", :class => "auth_provider"

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
%rss{:version => 2.0}
%channel
%title #{ENV['GROWSTUFF_SITE_NAME']} - Recent comments on all posts
%title Recent comments on all posts (#{ENV['GROWSTUFF_SITE_NAME']})
%link= comments_url
- @comments.each do |comment|
%item

View File

@@ -0,0 +1,16 @@
.alternate_names
%h4 Alternate names
- if crop.alternate_names.empty?
%p None known.
- else
%ul
- crop.alternate_names.each do |an|
%li
= an.name
- if can? :edit, an
= link_to 'Edit', edit_alternate_name_path(an), { :class => 'btn btn-default btn-xs' }
- if can? :destroy, an
= link_to 'Delete', an, method: :delete, data: { confirm: 'Are you sure?' }, :class => 'btn btn-default btn-xs'
%p
- if can? :edit, crop
= link_to 'Add', new_alternate_name_path( :crop_id => crop.id ), { :class => 'btn btn-default btn-xs' }

View File

@@ -1,4 +1,4 @@
%h4 Find seeds
%h4 Find #{ crop.name } seeds
- if crop.seeds.empty?
%p
There are no seeds available to trade.

View File

@@ -1,5 +1,7 @@
- if ! crop.harvests.empty?
%p
%strong Grown for:
%p
%strong Grown for:
- if crop.harvests.empty?
not known.
- else
- popular_plant_parts = crop.popular_plant_parts.sort_by {|s, freq| freq }.reverse
!= popular_plant_parts.map {|p, freq| link_to(p, p) + " (#{freq})" }.join(", ")

View File

@@ -1,4 +1,4 @@
%h4 Harvests
%h4 #{ crop.name.capitalize } harvests
- if crop.harvests.empty?
%p
Nobody has harvested this crop yet.

View File

@@ -1,4 +1,4 @@
- cache "crop_image_#{crop.id}" do
- cache crop do
= link_to |
image_tag( |
crop.default_photo ? crop.default_photo.thumbnail_url : 'placeholder_150.png', |

View File

@@ -1,7 +1,7 @@
.well
.row
.col-md-4
= link_to image_tag((crop.default_photo ? crop.default_photo.thumbnail_url : 'placeholder_150.png'), :alt => '', :class => 'img-rounded crop-image'), crop
= link_to image_tag((crop.default_photo ? crop.default_photo.thumbnail_url : 'placeholder_150.png'), :alt => '', :class => 'img crop-image'), crop
.col-md-8
%h3{:style => 'padding-top: 0px; margin-top: 0px'}
= link_to crop, crop

View File

@@ -1,10 +1,15 @@
- if crop.planted_from.length > 0
%p
%strong Plant from:
%p
%strong Plant from:
- if crop.planted_from.empty?
not known.
- else
- planted_from = crop.planted_from.sort_by {|s, freq| freq }.reverse
= planted_from.map {|s, freq| "#{s} (#{freq})" }.join(", ")
- if crop.sunniness.length > 0
%p
%strong Plant in:
%p
%strong Plant in:
- if crop.sunniness.empty?
not known.
- else
- sunniness = crop.sunniness.sort_by {|s, freq| freq }.reverse
= sunniness.map {|s, freq| "#{s} (#{freq})" }.join(", ")

View File

@@ -1,4 +1,4 @@
%h4 Plantings
%h4 See who's planted #{ crop.name.pluralize }
- if crop.plantings.empty?
%p
Nobody has planted this crop yet.

View File

@@ -0,0 +1,16 @@
.scientific_names
%h4 Scientific names
- if crop.scientific_names.empty?
%p None known.
- else
%ul
- crop.scientific_names.each do |sn|
%li
= sn.scientific_name
- if can? :edit, sn
= link_to 'Edit', edit_scientific_name_path(sn), { :class => 'btn btn-default btn-xs' }
- if can? :destroy, sn
= link_to 'Delete', sn, method: :delete, data: { confirm: 'Are you sure?' }, :class => 'btn btn-default btn-xs'
%p
- if can? :edit, crop
= link_to 'Add', new_scientific_name_path( :crop_id => crop.id ), { :class => 'btn btn-default btn-xs' }

View File

@@ -1,14 +1,13 @@
.thumbnail(style='height: 220px')
- if crop
= link_to image_tag((crop.default_photo ? crop.default_photo.thumbnail_url : 'placeholder_150.png'), :alt => crop.name, :class => 'img-rounded'), crop
%p
= link_to crop.name, crop
- if crop.scientific_names.count > 0
%br/
%i
%small
.thumbnail
.crop-thumbnail
- if crop
= link_to image_tag((crop.default_photo ? crop.default_photo.thumbnail_url : 'placeholder_150.png'), :alt => crop.name, :class => 'img'), crop
.cropinfo
.cropname
= link_to crop.name, crop
- if crop.scientific_names.count > 0
.scientificname
= crop.scientific_names.first.scientific_name
%br/
%small
.plantingcount
Planted
= pluralize(crop.plantings.size, "time")

View File

@@ -4,7 +4,12 @@
is a variety of
= succeed "." do
= link_to crop.parent, crop.parent
- if crop.varieties.count > 0
%h3
Varieties:
- unless crop.varieties.empty?
%p
Varieties of #{crop.name}:
= render :partial => 'hierarchy', :locals => { :display_crops => [ crop ] }
- if ! crop.parent and crop.varieties.empty?
%p None known.

View File

@@ -0,0 +1,11 @@
- if can? :edit, crop or can? :destroy, crop
%h4 Crop wrangling
%p
You are a
= succeed "." do
%strong CROP WRANGLER
%p
- if can? :edit, crop
= link_to 'Edit crop', edit_crop_path(crop), { :class => 'btn btn-default btn-xs' }
- if can? :destroy, crop
= link_to 'Delete crop', crop, method: :delete, data: { confirm: 'Are you sure?' }, :class => 'btn btn-default btn-xs'

View File

@@ -5,5 +5,5 @@
= succeed "." do
= link_to "crops database", crops_path
- cache("full_crop_hierarchy") do
- cache cache_key_for(Crop) do
= render :partial => "hierarchy", :locals => { :display_crops => @crops }

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
%rss{:version => 2.0}
%channel
%title #{ENV['GROWSTUFF_SITE_NAME']} - Recently added crops
%title Recently added crops (#{ENV['GROWSTUFF_SITE_NAME']})
%link= crops_url
- @crops.each do |crop|
%item

View File

@@ -13,6 +13,8 @@
.row
.col-md-9
- unless current_member
Learn how to grow #{ @crop.name.pluralize } from growers around the world. #{ ENV['GROWSTUFF_SITE_NAME'] } has tips and advice from real-life growers, including when to plant #{ @crop.name.pluralize }, how to harvest #{ @crop.name.pluralize }, and more.
= render :partial => 'photos', :locals => { :crop => @crop }
@@ -34,69 +36,46 @@
%div#cropmap
%a{:name => 'posts'}
%div.pagination
= page_entries_info @posts, :model => "posts"
= will_paginate @posts, :params => {:anchor => "posts"}
%h2 What people are saying about #{ @crop.name.pluralize }
- unless @posts.empty?
- if @posts.empty?
%p
Nobody has posted about #{ @crop.name.pluralize } yet.
%p
- if can? :create, Post
= link_to "Post something", new_post_path, :class => 'btn btn-default'
- else
= render :partial => "shared/signin_signup", :locals => { :to => "post your tips and experiences growing #{ @crop.name.pluralize }" }
- else
%div.pagination
= page_entries_info @posts, :model => "posts"
= will_paginate @posts, :params => {:anchor => "posts"}
- @posts.each do |post|
= render :partial => "posts/single", :locals => { :post => post, :subject => true }
%div.pagination
= page_entries_info @posts, :model => "posts"
= will_paginate @posts, :params => {:anchor => "posts"}
%div.pagination
= page_entries_info @posts, :model => "posts"
= will_paginate @posts, :params => {:anchor => "posts"}
.col-md-3
- if can? :edit, @crop or can? :destroy, @crop
%h4 Crop wrangling
%p
You are a
= succeed "." do
%strong CROP WRANGLER
%p
- if can? :edit, @crop
= link_to 'Edit crop', edit_crop_path(@crop), { :class => 'btn btn-default btn-xs' }
- if can? :destroy, @crop
= link_to 'Delete crop', @crop, method: :delete, data: { confirm: 'Are you sure?' }, :class => 'btn btn-default btn-xs'
.scientific_names
%h4 Scientific names
%ul
- @crop.scientific_names.each do |sn|
%li
= sn.scientific_name
- if can? :edit, sn
= link_to 'Edit', edit_scientific_name_path(sn), { :class => 'btn btn-default btn-xs' }
- if can? :destroy, sn
= link_to 'Delete', sn, method: :delete, data: { confirm: 'Are you sure?' }, :class => 'btn btn-default btn-xs'
%p
- if can? :edit, @crop
= link_to 'Add', new_scientific_name_path( :crop_id => @crop.id ), { :class => 'btn btn-default btn-xs' }
= render :partial => 'wrangle', :locals => { :crop => @crop }
.alternate_names
%h4 Alternate names
%ul
- @crop.alternate_names.each do |an|
%li
= an.name
- if can? :edit, an
= link_to 'Edit', edit_alternate_name_path(an), { :class => 'btn btn-default btn-xs' }
- if can? :destroy, an
= link_to 'Delete', an, method: :delete, data: { confirm: 'Are you sure?' }, :class => 'btn btn-default btn-xs'
%p
- if can? :edit, @crop
= link_to 'Add', new_alternate_name_path( :crop_id => @crop.id ), { :class => 'btn btn-default btn-xs' }
= render :partial => 'varieties', :locals => { :crop => @crop }
%h4 How to grow #{ @crop.name.pluralize }
= render :partial => 'grown_for', :locals => { :crop => @crop }
= render :partial => 'planting_advice', :locals => { :crop => @crop }
%h4 More information
%ul
%li= link_to 'Wikipedia (English)', @crop.en_wikipedia_url
= render :partial => 'scientific_names', :locals => { :crop => @crop }
= render :partial => 'alternate_names', :locals => { :crop => @crop }
%h4 #{ @crop.name.capitalize } varieties
= render :partial => 'varieties', :locals => { :crop => @crop }
= render :partial => 'plantings', :locals => { :crop => @crop }
= render :partial => 'harvests', :locals => { :crop => @crop }
= render :partial => 'find_seeds', :locals => { :crop => @crop }
%h4 Learn more about #{ @crop.name.pluralize }
%ul
%li= link_to 'Wikipedia (English)', @crop.en_wikipedia_url

View File

@@ -1,19 +1,24 @@
.row
.col-md-6.hidden-xs
- cache "interesting_crops", :expires_in => 1.day do
.col-md-8
- cache cache_key_for(Crop, 'interesting'), :expires_in => 1.day do
%h2= t('.our_crops')
- Crop.interesting.each do |c|
.col-md-3{:style => 'margin:0px; padding: 3px'}
= render :partial => 'crops/image_with_popover', :locals => { :crop => c }
.hidden-xs
- Crop.interesting.first(8).each do |c|
.col-md-3
= render :partial => 'crops/thumbnail', :locals => { :crop => c }
.visible-xs
- Crop.interesting.first(3).each do |c|
.col-md-3
= render :partial => 'crops/thumbnail', :locals => { :crop => c }
.col-md-6
- cache "interesting_plantings" do
.col-md-4.hidden-xs
- cache cache_key_for(Planting) do
%h2= t('.recently_planted')
= render :partial => 'plantings/list', :locals => { :plantings => Planting.interesting.first(4) }
= render :partial => 'plantings/list', :locals => { :plantings => Planting.interesting.first(6) }
.row
.col-md-12
- cache "recent_crops" do
- cache cache_key_for(Crop, 'recent') do
%p{ :style => 'margin-top: 11.25px' }
%strong
#{t('.recently_added')}:

View File

@@ -1,11 +1,10 @@
%h2= t('.discussion')
- cache "recent_posts" do
- posts = Post.limit(6)
- if posts
=render :partial => "posts/summary", :locals => { :posts => posts, :howmany => 6 }
- posts = Post.limit(6)
- if posts
=render :partial => "posts/summary", :locals => { :posts => posts, :howmany => 6 }
- cache "homepage_forums" do
- cache cache_key_for(Forum) do
- forums = Forum.all
- if forums
%ul.list-inline

View File

@@ -1,14 +0,0 @@
%h2= t('.keep_in_touch')
%p
=image_tag("twitter_32.png", :alt => '')
= t('.twitter_html', link: link_to(t('.twitter_linktext'), 'http://twitter.com/growstufforg'))
%p
=image_tag("blog_32.png", :alt => '')
= t('.blog_html', link: link_to(t('.blog_linktext'), 'http://blog.growstuff.org/'))
%p
=image_tag("email_32.png", :alt => '')
= t('.newsletter_html', link: link_to(t('.newsletter_linktext'), 'http://blog.growstuff.org/newsletter'))

View File

@@ -1,4 +1,4 @@
- cache "interesting_members" do
- cache cache_key_for(Member) do
.hidden-xs
- members = Member.interesting.first(6)
- if members.present?
@@ -6,7 +6,7 @@
.row
- members.each do |m|
.col-md-6.homepage-members
.col-md-4.homepage-members
= render :partial => "members/thumbnail", :locals => { :member => m }
%p.text-right

View File

@@ -1,29 +0,0 @@
%h2= t('.open_source_title')
%p
= t('.open_source_body_html', why: link_to(t('.why_linktext'), 'http://blog.growstuff.org/2013/02/20/why-growstuff-is-open-source/'),
github: link_to(t('.github_linktext'), 'http://github.com/Growstuff/growstuff'),
site_name: ENV['GROWSTUFF_SITE_NAME'] )
%h2= t('.open_data_title')
%p
= t('.open_data_body_html', creative_commons_link: link_to(t('.creative_commons_linktext'), 'http://creativecommons.org/licenses/by-sa/3.0/'),
wiki_link: link_to(t('.wiki_linktext'), 'http://wiki.growstuff.org/index.php/Open_data'),
api_docs_link: link_to(t('.api_docs_linktext'), 'http://wiki.growstuff.org/index.php/API'))
%h2= t('.get_involved_title')
%p
= t('.get_involved_body_html', talk_link: link_to(t('.talk_linktext'), 'http://talk.growstuff.org/'),
wiki_link: link_to(t('.wiki_linktext'), 'http://wiki.growstuff.org/'))
%h2= t('.support_title')
%p
= t('.support_body_html', ad_free: link_to(t('.ad_free_linktext'), 'http://wiki.growstuff.org/index.php/Why_no_ads%3F'),
buy_account: link_to(t('.buy_account_linktext'), shop_path))

View File

@@ -3,7 +3,7 @@
%h2= t('.title')
- cache "interesting_seeds" do
- cache cache_key_for(Seed) do
- if seeds.length > 0
%table.table.table-striped

View File

@@ -17,13 +17,9 @@
= render :partial => 'blurb'
.visible-xs
= render :partial => 'blurb'
.row
.col-md-8.main
= render :partial => 'crops'
= render :partial => 'seeds'
= render :partial => 'members'
= render :partial => 'discuss'
.col-md-4.sidebar
= render :partial => 'keep_in_touch'
= render :partial => 'open'

View File

@@ -1,10 +1,29 @@
.navbar.navbar-default.navbar-bottom
.container
%ul.nav.navbar-nav.text-center
%li= link_to "About", "http://wiki.growstuff.org/index.php/About%20Growstuff"
%li= link_to "Contact", url_for(:controller => '/about', :action => 'contact')
%li= link_to "Terms of Service", url_for(:controller => '/policy', :action => 'tos')
%li= link_to "Privacy Policy", url_for(:controller => %'/policy', :action => 'privacy')
%li= link_to "Community Guidelines", url_for(:controller => '/policy', :action => 'community')
%li= link_to "Support/FAQ", url_for(:controller => '/support')
%li= link_to "Open Source", "https://github.com/Growstuff/growstuff"
.row
.col-md-4#about-growstuff
%ul
%li= link_to t('about'), "http://wiki.growstuff.org/index.php/About%20Growstuff"
%li= link_to t('our_values'), "http://wiki.growstuff.org/index.php/Values"
%li= link_to t('open_source'), "https://github.com/Growstuff/growstuff"
%li= link_to t('growstuff_team'), "http://wiki.growstuff.org/index.php/Team"
%li= link_to t('get_involved'), "http://wiki.growstuff.org/index.php/Get_involved"
.col-md-4#policies
%ul
%li= link_to t('terms_of_service'), url_for(:controller => '/policy', :action => 'tos')
%li= link_to t('privacy_policy'), url_for(:controller => '/policy', :action => 'privacy')
%li= link_to t('data_use_policy'), url_for(:controller => '/policy', :action => 'api')
%li= link_to t('community_guidelines'), url_for(:controller => '/policy', :action => 'community')
.col-md-4#contact
%ul
%li= link_to t('support_'), url_for(:controller => '/support')
%li= link_to t('contact'), url_for(:controller => '/about', :action => 'contact')
%p
= link_to('http://twitter.com/growstufforg', :target => "_blank") do
= image_tag("twitter_32.png", :alt => 'Twitter: @growstufforg')
&nbsp;
= link_to('https://www.facebook.com/Growstufforg', :target => "_blank") do
= image_tag("facebook_32.png", :alt => 'Facebook')
&nbsp;
= link_to('http://blog.growstuff.org/', :target => "_blank") do
= image_tag("blog_32.png", :alt => 'Growstuff Blog')

View File

@@ -9,7 +9,7 @@
%span.icon-bar
%span.icon-bar
%a.navbar-brand(href=root_path)
= image_tag("/assets/growstuff-brand.png", :size => "200x50", :alt => ENV['GROWSTUFF_SITE_NAME'])
= image_tag("growstuff-brand.png", :size => "200x50", :alt => ENV['GROWSTUFF_SITE_NAME'])
.navbar-collapse.collapse#navbar-collapse
%ul.nav.navbar-nav
%li.dropdown<

View File

@@ -16,5 +16,5 @@
= javascript_include_tag "http://html5shim.googlecode.com/svn/trunk/html5.js"
= stylesheet_link_tag "application", :media => "all"
%link(href="/assets/growstuff-apple-touch-icon-precomposed.png" rel="apple-touch-icon-precomposed")
= favicon_link_tag '/assets/favicon.ico'
%link(href="/growstuff-apple-touch-icon-precomposed.png" rel="apple-touch-icon-precomposed")
= favicon_link_tag 'favicon.ico'

View File

@@ -5,7 +5,7 @@
= render :partial => "layouts/header"
= render :partial => "layouts/crowdfunding"
.container
#maincontainer.container
.row
.col-md-12
- if content_for?(:title)

View File

@@ -9,4 +9,3 @@
= member.account_type
account

Some files were not shown because too many files have changed in this diff Show More