mirror of
https://github.com/Growstuff/growstuff.git
synced 2026-05-25 17:31:18 -04:00
Compare commits
325 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d6b83454fe | ||
|
|
d7ef598654 | ||
|
|
bd0da36d63 | ||
|
|
6dedf1b030 | ||
|
|
920ca2948b | ||
|
|
9e53105f43 | ||
|
|
6505254e6c | ||
|
|
ead9a250af | ||
|
|
3a9ec8cf6d | ||
|
|
c76e9ccbf6 | ||
|
|
1b62c5cb97 | ||
|
|
7bca5c8845 | ||
|
|
017df0484c | ||
|
|
d338bab82b | ||
|
|
35f8c126b6 | ||
|
|
eafe90e295 | ||
|
|
7b911034b8 | ||
|
|
798b89db11 | ||
|
|
506e3e550c | ||
|
|
8ab3167a28 | ||
|
|
436e7e3c59 | ||
|
|
9f1091a1c8 | ||
|
|
3b1e855da3 | ||
|
|
d7f8bff17a | ||
|
|
a7caa2fbaa | ||
|
|
b215ef03c7 | ||
|
|
3cbbbc79fb | ||
|
|
eb5e9e926b | ||
|
|
ef2d1eb683 | ||
|
|
965f87393d | ||
|
|
023333b15f | ||
|
|
2241a760c2 | ||
|
|
e4dabd1725 | ||
|
|
1dfac3fb2f | ||
|
|
d0f856d389 | ||
|
|
ac6aa730c1 | ||
|
|
cd12412b46 | ||
|
|
28288c51fe | ||
|
|
70cdab96c4 | ||
|
|
e906d293a2 | ||
|
|
abdc43ef40 | ||
|
|
3ed7edbfbf | ||
|
|
7e9f18e89e | ||
|
|
e09f050088 | ||
|
|
5bfab90b5b | ||
|
|
3289e7b950 | ||
|
|
102763f2ab | ||
|
|
09a78d4661 | ||
|
|
e0d8126514 | ||
|
|
5cceb2c4ff | ||
|
|
66fcad69fa | ||
|
|
2ab73d3df6 | ||
|
|
623dbdd418 | ||
|
|
78c4fc36b1 | ||
|
|
9ccef5471f | ||
|
|
0fc4c3cb4d | ||
|
|
c61f7b8e72 | ||
|
|
b81e034254 | ||
|
|
07f7572b13 | ||
|
|
2697fea249 | ||
|
|
cbb4f9d7ac | ||
|
|
0dbc2e1964 | ||
|
|
319fc12ebb | ||
|
|
2db7bf638b | ||
|
|
497121a221 | ||
|
|
e17a3a2ab1 | ||
|
|
49a5a26f17 | ||
|
|
b66b8263c1 | ||
|
|
c3429cc0f3 | ||
|
|
f7a2ec2054 | ||
|
|
95ecdad024 | ||
|
|
e6cbbb3e3d | ||
|
|
b78ccaa097 | ||
|
|
593d6e7ec1 | ||
|
|
4c6b96e590 | ||
|
|
8631c78f9a | ||
|
|
a69ad34359 | ||
|
|
1099e4c9fe | ||
|
|
3a53f4f8a8 | ||
|
|
076a6cc1df | ||
|
|
b842bff9cb | ||
|
|
80a28085f1 | ||
|
|
0dd8cbccf0 | ||
|
|
abece6473b | ||
|
|
ff1b941690 | ||
|
|
85a6eb6195 | ||
|
|
87bfceb035 | ||
|
|
b95975d632 | ||
|
|
075cdb8272 | ||
|
|
7db4dee61a | ||
|
|
0993917dc6 | ||
|
|
d6cb20e2c4 | ||
|
|
3e65656c7b | ||
|
|
47dc94f820 | ||
|
|
c1870d46a2 | ||
|
|
1988c22626 | ||
|
|
a795d452c6 | ||
|
|
656b0e44d8 | ||
|
|
af39df5e0c | ||
|
|
1f23e1a646 | ||
|
|
ca47127197 | ||
|
|
7ca89908cd | ||
|
|
2c94f61843 | ||
|
|
7326acba81 | ||
|
|
77b4b76f14 | ||
|
|
eca27d18ea | ||
|
|
2f67ffd2f8 | ||
|
|
40d13fadb3 | ||
|
|
3791f4aa6f | ||
|
|
79c60dc7c7 | ||
|
|
5035b65883 | ||
|
|
4211ebec76 | ||
|
|
d02edc3dd1 | ||
|
|
e86200b942 | ||
|
|
776b5450f9 | ||
|
|
c80b42d9bc | ||
|
|
6aa37e6e26 | ||
|
|
089a3d5c24 | ||
|
|
1741567e19 | ||
|
|
de5b16e384 | ||
|
|
a8c203aea0 | ||
|
|
2aa30475e9 | ||
|
|
9a5e15b292 | ||
|
|
bb9695b272 | ||
|
|
d436fd86f8 | ||
|
|
3f393b0937 | ||
|
|
fb271633d9 | ||
|
|
e40fad76fd | ||
|
|
41db12d8d7 | ||
|
|
28d29291a7 | ||
|
|
22e0379769 | ||
|
|
b60bbbcb4e | ||
|
|
0da121a48d | ||
|
|
6b6ffd6e58 | ||
|
|
21dbf87ab9 | ||
|
|
a5fcd9f860 | ||
|
|
2853bf5c70 | ||
|
|
2d55d88db8 | ||
|
|
2567e7cd74 | ||
|
|
e2bac619b7 | ||
|
|
0bdab0d9fc | ||
|
|
e55fe55dc7 | ||
|
|
5a474d523c | ||
|
|
d126392ee2 | ||
|
|
c38dc4661d | ||
|
|
675ac5a03f | ||
|
|
233f9dfd88 | ||
|
|
b414598b07 | ||
|
|
2c4e768a3a | ||
|
|
04d61bd040 | ||
|
|
5a96b7efd6 | ||
|
|
329e147add | ||
|
|
334b5bf63f | ||
|
|
58940a6765 | ||
|
|
2442539e1b | ||
|
|
b56237115e | ||
|
|
038192095d | ||
|
|
9a18b4b62b | ||
|
|
c6f5abc036 | ||
|
|
ad76a04e8f | ||
|
|
0b70be4939 | ||
|
|
da2590791e | ||
|
|
79a7958519 | ||
|
|
f4d452f3bc | ||
|
|
d08e2f09db | ||
|
|
d5cc3f300a | ||
|
|
1982cecc31 | ||
|
|
2f05f1dbdb | ||
|
|
a67a55c599 | ||
|
|
253b5a3f85 | ||
|
|
45aaf31722 | ||
|
|
d0b9917e84 | ||
|
|
32dcacf9ba | ||
|
|
0e0c309c15 | ||
|
|
dabfeeea3c | ||
|
|
20b9996f14 | ||
|
|
1ea5257da4 | ||
|
|
3c360ab1b8 | ||
|
|
b1c60572ef | ||
|
|
14ad572f18 | ||
|
|
1481d01cf8 | ||
|
|
492781ea3d | ||
|
|
542d978d9c | ||
|
|
c893dcd271 | ||
|
|
57552455e3 | ||
|
|
fe69e2f11d | ||
|
|
684a3d2229 | ||
|
|
3d738e1b7c | ||
|
|
a5daa156ab | ||
|
|
018b2b4711 | ||
|
|
d12ec968c4 | ||
|
|
531a0bd9ea | ||
|
|
7950c577e9 | ||
|
|
3bc77f9b09 | ||
|
|
05260c05c2 | ||
|
|
d0ea54237e | ||
|
|
f404d54d02 | ||
|
|
5a2d9eabf4 | ||
|
|
1b936100e7 | ||
|
|
34ea6eb37f | ||
|
|
2c006ec430 | ||
|
|
f541261e43 | ||
|
|
f910fdfa73 | ||
|
|
72f86c4ad0 | ||
|
|
0cb192ce36 | ||
|
|
3aadc5d68f | ||
|
|
1387f381d2 | ||
|
|
7257f2e557 | ||
|
|
025bfdb4b0 | ||
|
|
1a50566328 | ||
|
|
ae914daa0c | ||
|
|
b984475335 | ||
|
|
59f5101858 | ||
|
|
e7d3e4d6dd | ||
|
|
79e1835216 | ||
|
|
e4072fb395 | ||
|
|
666d6dac48 | ||
|
|
ea5b340933 | ||
|
|
534c299383 | ||
|
|
99eb33ccbb | ||
|
|
760e5ca74e | ||
|
|
cd57c9cd34 | ||
|
|
2a184bcb2e | ||
|
|
df63819602 | ||
|
|
628d5b24c1 | ||
|
|
8221d5b441 | ||
|
|
ad7cfdabd0 | ||
|
|
4237dfb269 | ||
|
|
c512b079fa | ||
|
|
b4cd151a03 | ||
|
|
eab958eac4 | ||
|
|
17e94e01d0 | ||
|
|
6451077d1d | ||
|
|
ce265e281a | ||
|
|
f4511c79e6 | ||
|
|
06c7703628 | ||
|
|
619e8590c8 | ||
|
|
88efcf4da6 | ||
|
|
556ba33172 | ||
|
|
9d7b939d42 | ||
|
|
0bea278c5c | ||
|
|
65814f1ef6 | ||
|
|
1a7fc57f66 | ||
|
|
db0eb3e4da | ||
|
|
175996ce90 | ||
|
|
323f635b7b | ||
|
|
f70f82014f | ||
|
|
8756808444 | ||
|
|
bb6e798bce | ||
|
|
a5c226d128 | ||
|
|
729dba8e0b | ||
|
|
85c3e74cdd | ||
|
|
c7bcbf6323 | ||
|
|
f3302a9e30 | ||
|
|
1e331fc19d | ||
|
|
31a7011260 | ||
|
|
181c36cdc9 | ||
|
|
36ac0b75e7 | ||
|
|
f9cec41360 | ||
|
|
19dcf6f3d5 | ||
|
|
d5aef16860 | ||
|
|
1d28c30680 | ||
|
|
9a3c4e69e8 | ||
|
|
55ba535353 | ||
|
|
56025d3d33 | ||
|
|
59cae7a8ce | ||
|
|
9a9f859b70 | ||
|
|
ba3a1f6298 | ||
|
|
10e6e7c3cb | ||
|
|
a510489570 | ||
|
|
fcbc6002d1 | ||
|
|
eeb48e2ad6 | ||
|
|
b114ed2414 | ||
|
|
1064f39020 | ||
|
|
b5a460a1b7 | ||
|
|
9a961b80e5 | ||
|
|
7bc05fa118 | ||
|
|
f7af7e649d | ||
|
|
4efb93ea45 | ||
|
|
a5edb6497c | ||
|
|
d6314ea9a1 | ||
|
|
c244ca672f | ||
|
|
401777cc4c | ||
|
|
7ef8afb1ba | ||
|
|
e25bb5578a | ||
|
|
401f3e176e | ||
|
|
10ae117914 | ||
|
|
86cea2ad9f | ||
|
|
ccef46a5cf | ||
|
|
c803da3dfa | ||
|
|
02ff45f705 | ||
|
|
8a05a959c3 | ||
|
|
e5d407b1ce | ||
|
|
5cd53be5be | ||
|
|
c6cc8ee6bb | ||
|
|
eaf4ea04ac | ||
|
|
007f7112a7 | ||
|
|
f62fd8484a | ||
|
|
849bdac81b | ||
|
|
c1d2f2c9cc | ||
|
|
d92d22d99c | ||
|
|
8829acba3f | ||
|
|
66c4a19ad6 | ||
|
|
a65b78084f | ||
|
|
cdaa9c03a2 | ||
|
|
a35a573b2b | ||
|
|
314cdc687a | ||
|
|
df3b300967 | ||
|
|
d174f25d03 | ||
|
|
cf7ead3d84 | ||
|
|
18c40809a6 | ||
|
|
c83b01bbb7 | ||
|
|
fb595de457 | ||
|
|
acbd3f9a9e | ||
|
|
98c1680138 | ||
|
|
0ffe9adc86 | ||
|
|
56b4f8a221 | ||
|
|
f1945151c7 | ||
|
|
cc31e864d5 | ||
|
|
868e5c2079 | ||
|
|
70185156aa | ||
|
|
7fc886f43c | ||
|
|
8e79199766 | ||
|
|
40a88b5b09 | ||
|
|
c6f56a23d6 |
42
.travis.yml
42
.travis.yml
@@ -1,12 +1,38 @@
|
||||
---
|
||||
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' GROWSTUFF_ELASTICSEARCH='true'
|
||||
- GROWSTUFF_SITE_NAME="Growstuff (travis)" RAILS_SECRET_TOKEN='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' GROWSTUFF_ELASTICSEARCH='false'
|
||||
global:
|
||||
secure: "Z5TpM2jEX4UCvNePnk/LwltQX48U2u9BRc+Iypr1x9QW2o228QJhPIOH39a8RMUrepGnkQIq9q3ZRUn98RfrJz1yThtlNFL3NmzdQ57gKgjGwfpa0e4Dwj/ZJqV2D84tDGjvdVYLP7zzaYZxQcwk/cgNpzKf/jq97HLNP7CYuf4="
|
||||
bundler_args: "--without development production staging"
|
||||
rvm:
|
||||
- 2.1.5
|
||||
- 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/
|
||||
services:
|
||||
- elasticsearch
|
||||
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
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -40,7 +41,6 @@ submit the change with your pull request.
|
||||
- Marty Hines / [martyhines](https://github.com/martyhines)
|
||||
- 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)
|
||||
@@ -51,4 +51,7 @@ submit the change with your pull request.
|
||||
- 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)
|
||||
- Robert Landreaux / [robertlandreaux](https://github.com/robertlandreaux)
|
||||
- Savant Krishna / [sksavant](https://github.com/sksavant)
|
||||
|
||||
|
||||
165
Gemfile
165
Gemfile
@@ -1,92 +1,55 @@
|
||||
source 'https://rubygems.org'
|
||||
|
||||
ruby "2.1.5"
|
||||
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 'cancancan', '~> 1.9' # for checking member privileges
|
||||
gem 'gibbon' # for Mailchimp newsletter subscriptions
|
||||
gem 'csv_shaper' # CSV export
|
||||
gem 'ruby-units' # for unit conversion
|
||||
|
||||
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 'comfortable_mexican_sofa', '~> 1.12.0' # content management system
|
||||
|
||||
# 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.7'
|
||||
|
||||
# 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 +58,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'
|
||||
@@ -116,18 +79,48 @@ gem 'omniauth'
|
||||
gem 'omniauth-twitter'
|
||||
gem 'omniauth-flickr', '>= 0.0.15'
|
||||
|
||||
# client for Elasticsearch. Elasticsearch is a flexible
|
||||
# and powerful, distributed, real-time search and analytics engine.
|
||||
# An example of the use in the project is fuzzy crop search.
|
||||
gem "elasticsearch-model"
|
||||
gem "elasticsearch-rails"
|
||||
|
||||
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
|
||||
gem 'bonsai-elasticsearch-rails' # Integration with Bonsa-Elasticsearch on heroku
|
||||
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
|
||||
|
||||
324
Gemfile.lock
324
Gemfile.lock
@@ -20,35 +20,39 @@ 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)
|
||||
active_link_to (1.0.2)
|
||||
actionpack
|
||||
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)
|
||||
autoprefixer-rails (5.1.1)
|
||||
execjs
|
||||
json
|
||||
bcrypt (3.1.9)
|
||||
better_errors (2.0.0)
|
||||
coderay (>= 1.0.0)
|
||||
@@ -57,14 +61,19 @@ GEM
|
||||
binding_of_caller (0.7.2)
|
||||
debug_inspector (>= 0.0.1)
|
||||
bluecloth (2.2.0)
|
||||
bonsai-elasticsearch-rails (0.0.4)
|
||||
bootstrap-datepicker-rails (1.3.0.2)
|
||||
railties (>= 3.0)
|
||||
builder (3.0.4)
|
||||
bootstrap-sass (3.3.3)
|
||||
autoprefixer-rails (>= 5.0.0.1)
|
||||
sass (>= 3.2.19)
|
||||
bootstrap_form (2.2.0)
|
||||
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 +83,38 @@ GEM
|
||||
capybara-email (2.4.0)
|
||||
capybara (~> 2.4)
|
||||
mail
|
||||
chunky_png (1.3.3)
|
||||
climate_control (0.0.3)
|
||||
activesupport (>= 3.0)
|
||||
cliver (0.3.2)
|
||||
cocaine (0.5.5)
|
||||
climate_control (>= 0.0.3, < 1.0)
|
||||
codemirror-rails (4.8)
|
||||
railties (>= 3.0, < 5)
|
||||
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)
|
||||
comfortable_mexican_sofa (1.12.7)
|
||||
active_link_to (>= 1.0.0)
|
||||
bootstrap-sass (>= 3.2.0)
|
||||
bootstrap_form (>= 2.2.0)
|
||||
codemirror-rails (>= 3.0.0)
|
||||
coffee-rails (>= 3.1.0)
|
||||
haml-rails (>= 0.3.0)
|
||||
jquery-rails (>= 3.0.0)
|
||||
jquery-ui-rails (>= 5.0.0)
|
||||
kramdown (>= 1.0.0)
|
||||
paperclip (>= 4.0.0)
|
||||
plupload-rails (>= 1.2.1)
|
||||
rails (>= 4.0.0, < 5)
|
||||
rails-i18n (>= 4.0.0)
|
||||
sass-rails (>= 4.0.3)
|
||||
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,51 +127,77 @@ 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
|
||||
elasticsearch (1.0.6)
|
||||
elasticsearch-api (= 1.0.6)
|
||||
elasticsearch-transport (= 1.0.6)
|
||||
elasticsearch-api (1.0.6)
|
||||
multi_json
|
||||
elasticsearch-model (0.1.6)
|
||||
activesupport (> 3)
|
||||
elasticsearch (> 0.4)
|
||||
hashie
|
||||
elasticsearch-rails (0.1.6)
|
||||
elasticsearch-transport (1.0.6)
|
||||
faraday
|
||||
multi_json
|
||||
erubis (2.7.0)
|
||||
excon (0.43.0)
|
||||
execjs (2.2.2)
|
||||
factory_girl (4.5.0)
|
||||
activesupport (>= 3.0.0)
|
||||
factory_girl_rails (4.5.0)
|
||||
factory_girl (~> 4.5.0)
|
||||
railties (>= 3.0.0)
|
||||
faraday (0.9.1)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
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)
|
||||
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,17 +207,17 @@ 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)
|
||||
kramdown (1.5.0)
|
||||
launchy (2.4.3)
|
||||
addressable (~> 2.3)
|
||||
leaflet-markercluster-rails (0.7.0)
|
||||
@@ -181,20 +230,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.7)
|
||||
mail (2.5.4)
|
||||
mime-types (~> 1.16)
|
||||
treetop (~> 1.4.8)
|
||||
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.7.266)
|
||||
multipart-post (2.0.0)
|
||||
netrc (0.10.0)
|
||||
newrelic_rpm (3.9.8.273)
|
||||
nokogiri (1.6.5)
|
||||
mini_portile (~> 0.6.0)
|
||||
oauth (0.4.7)
|
||||
@@ -210,81 +260,104 @@ GEM
|
||||
multi_json (~> 1.3)
|
||||
omniauth-oauth (~> 1.0)
|
||||
orm_adapter (0.5.0)
|
||||
paperclip (4.2.1)
|
||||
activemodel (>= 3.0.0)
|
||||
activesupport (>= 3.0.0)
|
||||
cocaine (~> 0.5.3)
|
||||
mime-types
|
||||
pg (0.17.1)
|
||||
plupload-rails (1.2.1)
|
||||
rails (>= 3.1)
|
||||
poltergeist (1.5.1)
|
||||
capybara (~> 2.1)
|
||||
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-i18n (4.0.3)
|
||||
i18n (~> 0.6)
|
||||
railties (~> 4.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.4.0)
|
||||
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-units (1.4.5)
|
||||
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 +369,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 +384,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)
|
||||
@@ -327,33 +400,36 @@ DEPENDENCIES
|
||||
better_errors
|
||||
binding_of_caller
|
||||
bluecloth
|
||||
bonsai-elasticsearch-rails
|
||||
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)
|
||||
comfortable_mexican_sofa (~> 1.12.0)
|
||||
coveralls
|
||||
csv_shaper
|
||||
dalli
|
||||
database_cleaner (~> 1.3.0)
|
||||
devise (~> 3.2.0)
|
||||
factory_girl_rails (~> 4.0)
|
||||
devise (~> 3.4.1)
|
||||
elasticsearch-model
|
||||
elasticsearch-rails
|
||||
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)
|
||||
@@ -369,14 +445,16 @@ 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)
|
||||
ruby-units
|
||||
sass-rails (~> 4.0.4)
|
||||
therubyracer (~> 0.12)
|
||||
uglifier (>= 1.0.3)
|
||||
uglifier (~> 2.5.3)
|
||||
unicorn
|
||||
webrat
|
||||
will_paginate (~> 3.0)
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 572 B After Width: | Height: | Size: 613 B |
@@ -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
|
||||
|
||||
1
app/assets/javascripts/comfy/admin/cms/custom.js.coffee
Normal file
1
app/assets/javascripts/comfy/admin/cms/custom.js.coffee
Normal file
@@ -0,0 +1 @@
|
||||
# Custom JS for the admin area
|
||||
@@ -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
|
||||
|
||||
1
app/assets/stylesheets/comfy/admin/cms/custom.sass
Normal file
1
app/assets/stylesheets/comfy/admin/cms/custom.sass
Normal file
@@ -0,0 +1 @@
|
||||
// custom CSS for admin area
|
||||
@@ -122,7 +122,7 @@ p.stats {
|
||||
color: @brown;
|
||||
}
|
||||
|
||||
.crop-thumbnail {
|
||||
.photo-thumbnail {
|
||||
position:relative;
|
||||
padding:0;
|
||||
img {
|
||||
@@ -149,33 +149,55 @@ p.stats {
|
||||
}
|
||||
}
|
||||
|
||||
.member-thumbnail {
|
||||
img {
|
||||
height: 85px;
|
||||
width: 85px;
|
||||
max-width: 85px
|
||||
}
|
||||
}
|
||||
|
||||
.thumbnail {
|
||||
border: none;
|
||||
text-align: center;
|
||||
margin-bottom: 1.5em;
|
||||
|
||||
.scientific-name small, .crop-name a {
|
||||
display: inline-block;
|
||||
max-width: 100%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
line-height: 1em;
|
||||
padding-bottom: 2px;
|
||||
|
||||
.member-thumbnail {
|
||||
text-align: left;
|
||||
img {
|
||||
height: 85px;
|
||||
width: 85px;
|
||||
max-width: 85px
|
||||
}
|
||||
}
|
||||
|
||||
.crop-name a {
|
||||
padding-top: 2px;
|
||||
}
|
||||
.crop-thumbnail {
|
||||
height: 220px;
|
||||
.cropinfo {
|
||||
display: inline-block;
|
||||
max-width: 100%;
|
||||
white-space: nowrap;
|
||||
line-height: 1em;
|
||||
padding-bottom: 2px;
|
||||
|
||||
.scientific-name small {
|
||||
margin-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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,31 +214,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 {
|
||||
#footer1, #footer2, #footer3 {
|
||||
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%;
|
||||
@@ -244,6 +283,12 @@ footer .navbar .nav {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.alert {
|
||||
a {
|
||||
font-weight: 800;
|
||||
}
|
||||
}
|
||||
|
||||
// Overrides applying only to mobile view. This must be at the end of the overrides file.
|
||||
|
||||
@media only screen and (max-width: 767px) {
|
||||
@@ -261,3 +306,13 @@ footer .navbar .nav {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
/* override "info" alert boxes to be green, not blue, on Growstuff */
|
||||
@state-info-text: darken(@green, 10%);
|
||||
@state-info-bg: lighten(@green, 50%);
|
||||
|
||||
/* and set "success" to be the same, as it was just very slightly
|
||||
* different because the default bootstrap green is slightly different
|
||||
* from ours */
|
||||
@state-success-text: darken(@green, 10%);
|
||||
@state-success-bg: lighten(@green, 50%);
|
||||
|
||||
@@ -36,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
|
||||
@@ -52,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" }
|
||||
@@ -69,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
|
||||
|
||||
@@ -30,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" }
|
||||
@@ -38,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
|
||||
|
||||
@@ -45,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
|
||||
@@ -64,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
|
||||
@@ -88,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -2,15 +2,6 @@ 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']
|
||||
@@ -27,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."
|
||||
|
||||
@@ -2,8 +2,6 @@ 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
|
||||
@@ -55,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" }
|
||||
@@ -79,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
|
||||
@@ -101,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
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
require 'will_paginate/array'
|
||||
|
||||
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
|
||||
@sort = params[:sort]
|
||||
if @sort == 'alpha'
|
||||
# alphabetical order
|
||||
@crops = Crop.includes(:scientific_names, {:plantings => :photos}).paginate(:page => params[:page])
|
||||
@crops = Crop.includes(:scientific_names, {:plantings => :photos})
|
||||
@paginated_crops = @crops.approved.paginate(:page => params[:page])
|
||||
else
|
||||
# default to sorting by popularity
|
||||
@crops = Crop.popular.includes(:scientific_names, {:plantings => :photos}).paginate(:page => params[:page])
|
||||
@crops = Crop.popular.includes(:scientific_names, {:plantings => :photos})
|
||||
@paginated_crops = @crops.approved.paginate(:page => params[:page])
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
@@ -34,7 +36,18 @@ class CropsController < ApplicationController
|
||||
|
||||
# GET /crops/wrangle
|
||||
def wrangle
|
||||
@crops = Crop.recent.paginate(:page => params[:page])
|
||||
@approval_status = params[:approval_status]
|
||||
case @approval_status
|
||||
when "pending"
|
||||
@crops = Crop.pending_approval
|
||||
when "rejected"
|
||||
@crops = Crop.rejected
|
||||
else
|
||||
@crops = Crop.recent
|
||||
end
|
||||
|
||||
@crops = @crops.paginate(:page => params[:page])
|
||||
|
||||
@crop_wranglers = Role.crop_wranglers
|
||||
respond_to do |format|
|
||||
format.html
|
||||
@@ -51,18 +64,13 @@ class CropsController < ApplicationController
|
||||
|
||||
# GET /crops/search
|
||||
def search
|
||||
@search = params[:search]
|
||||
@exact_match = Crop.find_by_name(params[:search])
|
||||
|
||||
@partial_matches = Crop.search(params[:search])
|
||||
# exclude exact match from partial match list
|
||||
@partial_matches.reject!{ |r| @exact_match && r.eql?(@exact_match) }
|
||||
|
||||
@fuzzy = Crop.search(params[:term])
|
||||
@term = params[:term]
|
||||
@matches = Crop.search(@term)
|
||||
@paginated_matches = @matches.paginate(:page => params[:page])
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.json { render :json => @fuzzy }
|
||||
format.json { render :json => @matches }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -98,17 +106,35 @@ class CropsController < ApplicationController
|
||||
# GET /crops/1/edit
|
||||
def edit
|
||||
@crop = Crop.find(params[:id])
|
||||
|
||||
(3 - @crop.scientific_names.length).times do
|
||||
@crop.scientific_names.build
|
||||
end
|
||||
end
|
||||
|
||||
# POST /crops
|
||||
# POST /crops.json
|
||||
def create
|
||||
params[:crop][:creator_id] = current_member.id
|
||||
@crop = Crop.new(params[:crop])
|
||||
@crop = Crop.new(crop_params)
|
||||
|
||||
if current_member.has_role? :crop_wrangler
|
||||
@crop.creator = current_member
|
||||
success_msg = "Crop was successfully created."
|
||||
else
|
||||
@crop.requester = current_member
|
||||
@crop.approval_status = "pending"
|
||||
success_msg = "Crop was successfully requested."
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
if @crop.save
|
||||
format.html { redirect_to @crop, notice: 'Crop was successfully created.' }
|
||||
unless current_member.has_role? :crop_wrangler
|
||||
Role.crop_wranglers.each do |w|
|
||||
Notifier.new_crop_request(w, @crop).deliver!
|
||||
end
|
||||
end
|
||||
|
||||
format.html { redirect_to @crop, notice: success_msg }
|
||||
format.json { render json: @crop, status: :created, location: @crop }
|
||||
else
|
||||
format.html { render action: "new" }
|
||||
@@ -122,8 +148,18 @@ class CropsController < ApplicationController
|
||||
def update
|
||||
@crop = Crop.find(params[:id])
|
||||
|
||||
previous_status = @crop.approval_status
|
||||
|
||||
@crop.creator = current_member if previous_status == "pending"
|
||||
|
||||
respond_to do |format|
|
||||
if @crop.update_attributes(params[:crop])
|
||||
if @crop.update(crop_params)
|
||||
if previous_status == "pending"
|
||||
requester = @crop.requester
|
||||
new_status = @crop.approval_status
|
||||
Notifier.crop_request_approved(requester, @crop).deliver! if new_status == "approved"
|
||||
Notifier.crop_request_rejected(requester, @crop).deliver! if new_status == "rejected"
|
||||
end
|
||||
format.html { redirect_to @crop, notice: 'Crop was successfully updated.' }
|
||||
format.json { head :no_content }
|
||||
else
|
||||
@@ -144,4 +180,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, :approval_status, :request_notes, :reason_for_rejection, :rejection_notes, :scientific_names_attributes => [:scientific_name, :_destroy, :id])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
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 => params[:followed_id])
|
||||
|
||||
@follow = current_member.follows.build(:followed_id => follow_params[:followed_id])
|
||||
|
||||
if @follow.save
|
||||
flash[:notice] = "Followed #{ @follow.followed.login_name }"
|
||||
@@ -15,11 +19,17 @@ class FollowsController < ApplicationController
|
||||
|
||||
# DELETE /follows/1
|
||||
def destroy
|
||||
@follow = current_member.follows.find(params[:id])
|
||||
@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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,8 +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
|
||||
@@ -50,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 }
|
||||
@@ -69,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
|
||||
@@ -84,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
|
||||
|
||||
@@ -20,7 +20,7 @@ class HarvestsController < ApplicationController
|
||||
format.html { @harvests = @harvests.paginate(:page => params[:page]) }
|
||||
format.json { render json: @harvests }
|
||||
format.csv do
|
||||
specifics = (@owner ? "#{@owner.name}-" : @crop ? "#{@crop.name}-" : nil)
|
||||
specifics = (@owner ? "#{@owner.login_name}-" : @crop ? "#{@crop.name}-" : nil)
|
||||
@filename = "Growstuff-#{specifics}Harvests-#{Time.zone.now.to_s(:number)}.csv"
|
||||
render :csv => @harvests
|
||||
end
|
||||
@@ -62,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
|
||||
@@ -81,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
|
||||
@@ -102,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, :si_weight)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
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])
|
||||
@sort = params[:sort]
|
||||
if @sort == 'recently_joined'
|
||||
@members = Member.confirmed.recently_joined.paginate(:page => params[:page])
|
||||
else
|
||||
@members = Member.confirmed.paginate(:page => params[:page])
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
format.html # index.html.haml
|
||||
@@ -44,4 +49,10 @@ class MembersController < ApplicationController
|
||||
@followers = @member.followers.paginate(:page => params[:page])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def expire_cache_fragments
|
||||
expire_fragment("homepage_stats")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -5,7 +5,7 @@ class NotificationsController < ApplicationController
|
||||
|
||||
# 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
|
||||
@@ -49,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|
|
||||
@@ -60,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
|
||||
|
||||
@@ -7,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|
|
||||
@@ -20,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
|
||||
|
||||
@@ -4,7 +4,7 @@ class OrdersController < ApplicationController
|
||||
|
||||
# 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
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
class PhotosController < ApplicationController
|
||||
before_filter :authenticate_member!, :except => [:index, :show]
|
||||
load_and_authorize_resource
|
||||
|
||||
cache_sweeper :photo_sweeper
|
||||
|
||||
# GET /photos
|
||||
# GET /photos.json
|
||||
@@ -61,13 +59,13 @@ 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
|
||||
|
||||
# several models can have photos. we need to know what model and the id
|
||||
# for the entry to attach the photo to
|
||||
valid_models = ["planting", "harvest"]
|
||||
valid_models = ["planting", "harvest", "garden"]
|
||||
if params[:type]
|
||||
if valid_models.include?(params[:type])
|
||||
if params[:id]
|
||||
@@ -111,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
|
||||
@@ -132,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
class PlantingsController < ApplicationController
|
||||
before_filter :authenticate_member!, :except => [:index, :show]
|
||||
load_and_authorize_resource
|
||||
|
||||
|
||||
cache_sweeper :planting_sweeper
|
||||
|
||||
# GET /plantings
|
||||
# GET /plantings.json
|
||||
@@ -33,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
|
||||
@@ -68,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 }
|
||||
@@ -90,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
|
||||
@@ -106,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
|
||||
|
||||
@@ -2,8 +2,6 @@ class PostsController < ApplicationController
|
||||
before_filter :authenticate_member!, :except => [:index, :show]
|
||||
load_and_authorize_resource
|
||||
|
||||
cache_sweeper :post_sweeper
|
||||
|
||||
# GET /posts
|
||||
# GET /posts.json
|
||||
|
||||
@@ -58,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
|
||||
@@ -77,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
|
||||
@@ -98,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
|
||||
|
||||
@@ -36,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
|
||||
@@ -52,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" }
|
||||
@@ -69,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
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -36,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
|
||||
@@ -52,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" }
|
||||
@@ -69,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
|
||||
|
||||
@@ -2,8 +2,6 @@ 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
|
||||
@@ -47,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
|
||||
@@ -66,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
|
||||
@@ -90,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
|
||||
|
||||
@@ -2,8 +2,6 @@ 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
|
||||
@@ -68,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
|
||||
@@ -87,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
|
||||
@@ -108,4 +106,13 @@ 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,
|
||||
:days_until_maturity_min, :days_until_maturity_max, :organic, :gmo,
|
||||
:heirloom, :tradable_to, :slug)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -19,4 +19,4 @@ module AutoSuggestHelper
|
||||
}.html_safe
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -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,
|
||||
@@ -22,4 +22,19 @@ class Notifier < ActionMailer::Base
|
||||
end
|
||||
end
|
||||
|
||||
def new_crop_request(member, request)
|
||||
@member, @request = member, request
|
||||
mail(:to => @member.email, :subject => "#{@request.requester.login_name} has requested #{@request.name} as a new crop")
|
||||
end
|
||||
|
||||
def crop_request_approved(member, crop)
|
||||
@member, @crop = member, crop
|
||||
mail(:to => @member.email, :subject => "#{crop.name.capitalize} has been approved")
|
||||
end
|
||||
|
||||
def crop_request_rejected(member, crop)
|
||||
@member, @crop = member, crop
|
||||
mail(:to => @member.email, :subject => "#{crop.name.capitalize} has been rejected")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -21,7 +21,24 @@ class Ability
|
||||
cannot :read, Account
|
||||
cannot :read, AccountType
|
||||
|
||||
# nobody should be able to view unapproved crops unless they
|
||||
# are wranglers or admins
|
||||
cannot :read, Crop
|
||||
can :read, Crop, :approval_status => "approved"
|
||||
# scientific names should only be viewable if associated crop is approved
|
||||
cannot :read, ScientificName
|
||||
can :read, ScientificName do |sn|
|
||||
sn.crop.approved?
|
||||
end
|
||||
# ... same for alternate names
|
||||
cannot :read, AlternateName
|
||||
can :read, AlternateName do |an|
|
||||
an.crop.approved?
|
||||
end
|
||||
|
||||
if member
|
||||
# members can see even rejected or pending crops if they requested it
|
||||
can :read, Crop, :requester_id => member.id
|
||||
|
||||
# managing your own user settings
|
||||
can :update, Member, :id => member.id
|
||||
@@ -45,6 +62,9 @@ class Ability
|
||||
can :manage, AlternateName
|
||||
end
|
||||
|
||||
# any member can create a crop provisionally
|
||||
can :create, Crop
|
||||
|
||||
# can create & destroy their own authentications against other sites.
|
||||
can :create, Authentication
|
||||
can :destroy, Authentication, :member_id => member.id
|
||||
@@ -94,9 +114,11 @@ class Ability
|
||||
cannot :destroy, OrderItem, :order => { :member_id => member.id, :completed_at => nil }
|
||||
|
||||
# following/unfollowing permissions
|
||||
can :create, Follow do |f|
|
||||
!member.already_following?(f.followed) && f.followed_id != member.id
|
||||
end
|
||||
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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
class AccountType < ActiveRecord::Base
|
||||
attr_accessible :is_paid, :is_permanent_paid, :name
|
||||
has_many :products
|
||||
|
||||
def to_s
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
class AlternateName < ActiveRecord::Base
|
||||
attr_accessible :crop_id, :name, :creator_id
|
||||
after_commit { |an| an.crop.__elasticsearch__.index_document if an.crop && ENV['GROWSTUFF_ELASTICSEARCH'] == "true" }
|
||||
belongs_to :crop
|
||||
belongs_to :creator, :class_name => 'Member'
|
||||
end
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
class Authentication < ActiveRecord::Base
|
||||
belongs_to :member
|
||||
attr_accessible :provider, :uid, :token, :secret, :name
|
||||
end
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -1,38 +1,115 @@
|
||||
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
|
||||
has_many :scientific_names, after_add: :update_index, after_remove: :update_index
|
||||
accepts_nested_attributes_for :scientific_names,
|
||||
:allow_destroy => true,
|
||||
:reject_if => :all_blank
|
||||
|
||||
has_many :alternate_names
|
||||
has_many :alternate_names, after_add: :update_index, after_remove: :update_index
|
||||
has_many :plantings
|
||||
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 :requester, :class_name => 'Member'
|
||||
|
||||
belongs_to :parent, :class_name => 'Crop'
|
||||
has_many :varieties, :class_name => 'Crop', :foreign_key => 'parent_id'
|
||||
has_and_belongs_to_many :posts
|
||||
before_destroy {|crop| crop.posts.clear}
|
||||
|
||||
default_scope { order("lower(name) asc") }
|
||||
scope :recent, -> { where(:approval_status => "approved").reorder("created_at desc") }
|
||||
scope :toplevel, -> { where(:approval_status => "approved", :parent_id => nil) }
|
||||
scope :popular, -> { where(:approval_status => "approved").reorder("plantings_count desc, lower(name) asc") }
|
||||
scope :randomized, -> { where(:approval_status => "approved").reorder('random()') } # ok on sqlite and psql, but not on mysql
|
||||
scope :pending_approval, -> { where(:approval_status => "pending") }
|
||||
scope :approved, -> { where(:approval_status => "approved") }
|
||||
scope :rejected, -> { where(:approval_status => "rejected") }
|
||||
|
||||
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
|
||||
|
||||
## Wikipedia urls are only necessary when approving a crop
|
||||
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'
|
||||
}
|
||||
},
|
||||
:if => :approved?
|
||||
|
||||
## Reasons are only necessary when rejecting
|
||||
validates :reason_for_rejection, :presence => true, :if => :rejected?
|
||||
|
||||
## This validation addresses a race condition
|
||||
validate :approval_status_cannot_be_changed_again
|
||||
|
||||
validate :must_be_rejected_if_rejected_reasons_present
|
||||
|
||||
validate :must_have_meaningful_reason_for_rejection
|
||||
|
||||
####################################
|
||||
# Elastic search configuration
|
||||
include Elasticsearch::Model
|
||||
include Elasticsearch::Model::Callbacks
|
||||
# In order to avoid clashing between different environments,
|
||||
# use Rails.env as a part of index name (eg. development_growstuff)
|
||||
index_name [Rails.env, "growstuff"].join('_')
|
||||
settings index: { number_of_shards: 1 },
|
||||
analysis: {
|
||||
tokenizer: {
|
||||
gs_edgeNGram_tokenizer: {
|
||||
type: "edgeNGram", # edgeNGram: NGram match from the start of a token
|
||||
min_gram: 3,
|
||||
max_gram: 10,
|
||||
# token_chars: Elasticsearch will split on characters
|
||||
# that don’t belong to any of these classes
|
||||
token_chars: [ "letter", "digit" ]
|
||||
}
|
||||
},
|
||||
analyzer: {
|
||||
gs_edgeNGram_analyzer: {
|
||||
tokenizer: "gs_edgeNGram_tokenizer",
|
||||
filter: ["lowercase"]
|
||||
}
|
||||
},
|
||||
} do
|
||||
mappings dynamic: 'false' do
|
||||
indexes :id, type: 'long'
|
||||
indexes :name, type: 'string', analyzer: 'gs_edgeNGram_analyzer'
|
||||
indexes :approval_status, type: 'string'
|
||||
indexes :scientific_names do
|
||||
indexes :scientific_name,
|
||||
type: 'string',
|
||||
analyzer: 'gs_edgeNGram_analyzer',
|
||||
# Disabling field-length norm (norm). If the norm option is turned on(by default),
|
||||
# higher weigh would be given for shorter fields, which in our case is irrelevant.
|
||||
norms: { enabled: false }
|
||||
end
|
||||
indexes :alternate_names do
|
||||
indexes :name, type: 'string', analyzer: 'gs_edgeNGram_analyzer'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def as_indexed_json(options={})
|
||||
self.as_json(
|
||||
only: [:id, :name, :approval_status],
|
||||
include: {
|
||||
scientific_names: { only: :scientific_name },
|
||||
alternate_names: { only: :name }
|
||||
})
|
||||
end
|
||||
|
||||
# update the Elasticsearch index (only if we're using it in this
|
||||
# environment)
|
||||
def update_index(name_obj)
|
||||
if ENV["GROWSTUFF_ELASTICSEARCH"] == "true"
|
||||
__elasticsearch__.index_document
|
||||
end
|
||||
end
|
||||
|
||||
# End Elasticsearch section
|
||||
|
||||
def to_s
|
||||
return name
|
||||
@@ -105,6 +182,26 @@ class Crop < ActiveRecord::Base
|
||||
return true
|
||||
end
|
||||
|
||||
def pending?
|
||||
approval_status == "pending"
|
||||
end
|
||||
|
||||
def approved?
|
||||
approval_status == "approved"
|
||||
end
|
||||
|
||||
def rejected?
|
||||
approval_status == "rejected"
|
||||
end
|
||||
|
||||
def approval_statuses
|
||||
[ 'rejected', 'pending', 'approved' ]
|
||||
end
|
||||
|
||||
def reasons_for_rejection
|
||||
[ "already in database", "not edible", "not enough information", "other" ]
|
||||
end
|
||||
|
||||
# Crop.interesting
|
||||
# returns a list of interesting crops, for use on the homepage etc
|
||||
def Crop.interesting
|
||||
@@ -132,7 +229,7 @@ class Crop < ActiveRecord::Base
|
||||
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
|
||||
@@ -202,11 +299,76 @@ class Crop < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
def rejection_explanation
|
||||
if reason_for_rejection == "other"
|
||||
return rejection_notes
|
||||
else
|
||||
return reason_for_rejection
|
||||
end
|
||||
end
|
||||
|
||||
# Crop.search(string)
|
||||
# searches for crops whose names match the string given
|
||||
# just uses SQL LIKE for now, but can be made fancier later
|
||||
def self.search(query)
|
||||
where("name ILIKE ?", "%#{query}%")
|
||||
if ENV['GROWSTUFF_ELASTICSEARCH'] == "true"
|
||||
search_str = query.nil? ? "" : query.downcase
|
||||
response = __elasticsearch__.search( {
|
||||
# Finds documents which match any field, but uses the _score from
|
||||
# the best field insead of adding up _score from each field.
|
||||
query: {
|
||||
multi_match: {
|
||||
query: "#{search_str}",
|
||||
analyzer: "standard",
|
||||
fields: ["name", "scientific_names.scientific_name", "alternate_names.name"]
|
||||
}
|
||||
},
|
||||
filter: {
|
||||
term: {approval_status: "approved"}
|
||||
},
|
||||
size: 50
|
||||
}
|
||||
)
|
||||
return response.records.to_a
|
||||
else
|
||||
# if we don't have elasticsearch, just do a basic SQL query.
|
||||
# also, make sure it's an actual array not an activerecord
|
||||
# collection, so it matches what we get from elasticsearch and we can
|
||||
# manipulate it in the same ways (eg. deleting elements without deleting
|
||||
# the whole record from the db)
|
||||
matches = Crop.approved.where("name ILIKE ?", "%#{query}%").to_a
|
||||
|
||||
# we want to make sure that exact matches come first, even if not
|
||||
# using elasticsearch (eg. in development)
|
||||
exact_match = Crop.approved.find_by_name(query)
|
||||
if exact_match
|
||||
matches.delete(exact_match)
|
||||
matches.unshift(exact_match)
|
||||
end
|
||||
|
||||
return matches
|
||||
end
|
||||
end
|
||||
|
||||
# Custom validations
|
||||
|
||||
def approval_status_cannot_be_changed_again
|
||||
previous = previous_changes.include?(:approval_status) ? previous_changes.approval_status : {}
|
||||
if previous.include?(:rejected) || previous.include?(:approved)
|
||||
errors.add(:approval_status, "has already been set to #{approval_status}")
|
||||
end
|
||||
end
|
||||
|
||||
def must_be_rejected_if_rejected_reasons_present
|
||||
unless rejected?
|
||||
if reason_for_rejection.present? || rejection_notes.present?
|
||||
errors.add(:approval_status, "must be rejected if a reason for rejection is present")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def must_have_meaningful_reason_for_rejection
|
||||
if reason_for_rejection == "other" && rejection_notes.blank?
|
||||
errors.add(:rejection_notes, "must be added if the reason for rejection is \"other\"")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
class Follow < ActiveRecord::Base
|
||||
attr_accessible :followed_id, :follower_id
|
||||
belongs_to :follower, class_name: "Member"
|
||||
belongs_to :followed, class_name: "Member"
|
||||
validates :follower_id, uniqueness: { :scope => :followed_id }
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -1,24 +1,32 @@
|
||||
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
|
||||
|
||||
has_and_belongs_to_many :photos
|
||||
|
||||
before_destroy do |garden|
|
||||
photolist = garden.photos.to_a # save a temp copy of the photo list
|
||||
garden.photos.clear # clear relationship b/w garden and photo
|
||||
|
||||
photolist.each do |photo|
|
||||
photo.destroy_if_unused
|
||||
end
|
||||
end
|
||||
|
||||
# set up geocoding
|
||||
geocoded_by :location
|
||||
after_validation :geocode
|
||||
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 => {
|
||||
@@ -26,7 +34,9 @@ class Garden < ActiveRecord::Base
|
||||
}
|
||||
|
||||
validates :area,
|
||||
:numericality => { :only_integer => false, :greater_than_or_equal_to => 0 },
|
||||
:numericality => {
|
||||
:only_integer => false,
|
||||
:greater_than_or_equal_to => 0 },
|
||||
:allow_nil => true
|
||||
|
||||
AREA_UNITS_VALUES = {
|
||||
@@ -86,4 +96,8 @@ class Garden < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
def default_photo
|
||||
return photos.first
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
friendly_id :harvest_slug, use: [:slugged, :finders]
|
||||
|
||||
belongs_to :crop
|
||||
belongs_to :owner, :class_name => 'Member'
|
||||
@@ -21,12 +18,16 @@ class Harvest < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
default_scope order('created_at DESC')
|
||||
default_scope { order('created_at DESC') }
|
||||
|
||||
validates :crop, :approved => true
|
||||
|
||||
validates :crop, :presence => {:message => "must be present and exist in our database"}
|
||||
|
||||
validates :quantity,
|
||||
:numericality => { :only_integer => false },
|
||||
:numericality => {
|
||||
:only_integer => false,
|
||||
:greater_than_or_equal_to => 0 },
|
||||
:allow_nil => true
|
||||
|
||||
UNITS_VALUES = {
|
||||
@@ -62,6 +63,17 @@ class Harvest < ActiveRecord::Base
|
||||
|
||||
after_validation :cleanup_quantities
|
||||
|
||||
before_save :set_si_weight
|
||||
|
||||
# we're storing the harvest weight in kilograms in the db too
|
||||
# to make data manipulation easier
|
||||
def set_si_weight
|
||||
if self.weight_unit != nil
|
||||
weight_string = "#{self.weight_quantity} #{self.weight_unit}"
|
||||
self.si_weight = Unit(weight_string).convert_to("kg").to_s("%0.3f").delete(" kg").to_f
|
||||
end
|
||||
end
|
||||
|
||||
def cleanup_quantities
|
||||
if quantity == 0
|
||||
self.quantity = nil
|
||||
|
||||
@@ -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,18 +27,20 @@ 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 :recently_joined, -> { reorder("confirmed_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
|
||||
|
||||
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)
|
||||
|
||||
# Include default devise modules. Others available are:
|
||||
# :token_authenticatable, :confirmable,
|
||||
# :lockable, :timeoutable and :omniauthable
|
||||
@@ -46,16 +48,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
|
||||
@@ -80,7 +72,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 => {
|
||||
@@ -93,7 +85,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
|
||||
|
||||
@@ -243,17 +235,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'],
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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/,
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
class OrderItem < ActiveRecord::Base
|
||||
attr_accessible :order_id, :price, :product_id, :quantity
|
||||
|
||||
belongs_to :order
|
||||
belongs_to :product
|
||||
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
class Photo < ActiveRecord::Base
|
||||
attr_accessible :flickr_photo_id, :owner_id, :title, :license_name,
|
||||
:license_url, :thumbnail_url, :fullsize_url, :link_url
|
||||
belongs_to :owner, :class_name => 'Member'
|
||||
|
||||
has_and_belongs_to_many :plantings
|
||||
has_and_belongs_to_many :harvests
|
||||
has_and_belongs_to_many :gardens
|
||||
before_destroy do |photo|
|
||||
photo.plantings.clear
|
||||
photo.harvests.clear
|
||||
photo.gardens.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
|
||||
unless plantings.size > 0 or harvests.size > 0
|
||||
unless plantings.size > 0 or harvests.size > 0 or gardens.size > 0
|
||||
self.destroy
|
||||
end
|
||||
end
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,12 +28,16 @@ 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"}
|
||||
validates :crop, :approved => true
|
||||
|
||||
validates :crop, :presence => {:message => "must be present and exist in our database"}
|
||||
|
||||
validates :quantity,
|
||||
:numericality => { :only_integer => true },
|
||||
:numericality => {
|
||||
:only_integer => true,
|
||||
:greater_than_or_equal_to => 0 },
|
||||
:allow_nil => true
|
||||
|
||||
SUNNINESS_VALUES = %w(sun semi-shade shade)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
@@ -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
|
||||
@@ -1,12 +1,12 @@
|
||||
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
|
||||
|
||||
validates :paid_months, :numericality => { :only_integer => true,
|
||||
:allow_nil => true }
|
||||
validates :paid_months,
|
||||
:numericality => {
|
||||
:only_integer => true,
|
||||
:greater_than_or_equal_to => 0 },
|
||||
:allow_nil => true
|
||||
|
||||
def to_s
|
||||
name
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
class ScientificName < ActiveRecord::Base
|
||||
attr_accessible :crop_id, :scientific_name, :creator_id
|
||||
after_commit { |sn| sn.crop.__elasticsearch__.index_document if sn.crop && ENV['GROWSTUFF_ELASTICSEARCH'] == "true" }
|
||||
belongs_to :crop
|
||||
belongs_to :creator, :class_name => 'Member'
|
||||
end
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,21 +1,32 @@
|
||||
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, :approved => true
|
||||
|
||||
validates :crop, :presence => {:message => "must be present and exist in our database"}
|
||||
validates :quantity,
|
||||
:numericality => { :only_integer => true },
|
||||
:numericality => {
|
||||
:only_integer => true,
|
||||
:greater_than_or_equal_to => 0 },
|
||||
:allow_nil => true
|
||||
validates :days_until_maturity_min,
|
||||
:numericality => {
|
||||
:only_integer => true,
|
||||
:greater_than_or_equal_to => 0 },
|
||||
:allow_nil => true
|
||||
validates :days_until_maturity_max,
|
||||
:numericality => {
|
||||
:only_integer => true,
|
||||
:greater_than_or_equal_to => 0 },
|
||||
: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,
|
||||
@@ -23,6 +34,32 @@ class Seed < ActiveRecord::Base
|
||||
:allow_nil => false,
|
||||
:allow_blank => false
|
||||
|
||||
ORGANIC_VALUES = [
|
||||
'certified organic',
|
||||
'non-certified organic',
|
||||
'conventional/non-organic',
|
||||
'unknown']
|
||||
validates :organic, :inclusion => { :in => ORGANIC_VALUES,
|
||||
:message => "You must say whether the seeds are organic or not, or that you don't know" },
|
||||
:allow_nil => false,
|
||||
:allow_blank => false
|
||||
|
||||
GMO_VALUES = [
|
||||
'certified GMO-free',
|
||||
'non-certified GMO-free',
|
||||
'GMO',
|
||||
'unknown']
|
||||
validates :gmo, :inclusion => { :in => GMO_VALUES,
|
||||
:message => "You must say whether the seeds are genetically modified or not, or that you don't know" },
|
||||
:allow_nil => false,
|
||||
:allow_blank => false
|
||||
|
||||
HEIRLOOM_VALUES = %w(heirloom hybrid unknown)
|
||||
validates :heirloom, :inclusion => { :in => HEIRLOOM_VALUES,
|
||||
:message => "You must say whether the seeds are heirloom, hybrid, or unknown" },
|
||||
:allow_nil => false,
|
||||
:allow_blank => false
|
||||
|
||||
def tradable?
|
||||
if self.tradable_to == 'nowhere'
|
||||
return false
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
7
app/validators/approved_validator.rb
Normal file
7
app/validators/approved_validator.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
class ApprovedValidator < ActiveModel::EachValidator
|
||||
def validate_each(record, attribute, value)
|
||||
unless record.crop.try(:approved?)
|
||||
record.errors[attribute] << (options[:message] || 'must be approved')
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -8,6 +8,7 @@
|
||||
%li= link_to "Roles", roles_path
|
||||
%li= link_to "Forums", forums_path
|
||||
%li= link_to "Newsletter subscribers", admin_newsletter_path
|
||||
%li= link_to "CMS", comfy_admin_cms_path
|
||||
|
||||
%h2 Orders
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
%p#notice= notice
|
||||
|
||||
= render :partial => 'crops/approval_status_message', :locals => { :crop => @alternate_name.crop }
|
||||
|
||||
%p
|
||||
%b Alternate name:
|
||||
= @alternate_name.name
|
||||
|
||||
@@ -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"
|
||||
11
app/views/crops/_approval_status_message.html.haml
Normal file
11
app/views/crops/_approval_status_message.html.haml
Normal file
@@ -0,0 +1,11 @@
|
||||
- if crop.pending?
|
||||
.alert.alert-danger
|
||||
%b This crop is currently pending approval.
|
||||
%p This crop was requested by #{crop.requester} #{time_ago_in_words(crop.created_at)} ago.
|
||||
- unless crop.request_notes.blank?
|
||||
%p
|
||||
Request notes: #{crop.request_notes}
|
||||
|
||||
- if crop.rejected?
|
||||
.alert.alert-danger
|
||||
%b This crop was rejected for the following reason: #{crop.rejection_explanation}
|
||||
@@ -1,4 +1,4 @@
|
||||
%h4 Find seeds
|
||||
%h4 Find #{ crop.name } seeds
|
||||
- if crop.seeds.empty?
|
||||
%p
|
||||
There are no seeds available to trade.
|
||||
@@ -10,7 +10,8 @@
|
||||
= render :partial => 'members/location', :locals => { :member => seed.owner }
|
||||
%p
|
||||
= link_to "View all #{crop.name} seeds", seeds_by_crop_path(crop)
|
||||
- if current_member
|
||||
= link_to "List achiote seeds to trade", new_seed_path(:crop_id => crop.id)
|
||||
- else
|
||||
= render :partial => 'shared/signin_signup', :locals => { :to => 'list your seeds to trade' }
|
||||
- if crop.approved?
|
||||
- if current_member
|
||||
%p= link_to "List #{crop.name} seeds to trade", new_seed_path(:crop_id => crop.id)
|
||||
- else
|
||||
= render :partial => 'shared/signin_signup', :locals => { :to => 'list your seeds to trade' }
|
||||
|
||||
@@ -6,30 +6,47 @@
|
||||
- @crop.errors.full_messages.each do |msg|
|
||||
%li= msg
|
||||
|
||||
%p
|
||||
%span.help-block
|
||||
For detailed crop wrangling guidelines, please consult the
|
||||
=link_to "crop wrangling guide", "http://wiki.growstuff.org/index.php/Crop_wrangling"
|
||||
on the Growstuff wiki.
|
||||
-# Handy link to crop wrangling policy/style guide, shown to wranglers only
|
||||
- if can? :wrangle, @crop
|
||||
%p
|
||||
%span.help-block
|
||||
For detailed crop wrangling guidelines, please consult the
|
||||
=link_to "crop wrangling guide", "http://wiki.growstuff.org/index.php/Crop_wrangling"
|
||||
on the Growstuff wiki.
|
||||
|
||||
-# Everyone (wranglers and requesters) sees the basic info section
|
||||
%h2 Basic information
|
||||
|
||||
.form-group
|
||||
= f.label :name, :class => 'control-label col-md-2'
|
||||
.col-md-8
|
||||
= f.text_field :name, :class => 'form-control'
|
||||
%span.help-block Name in US English; singular; capitalize proper nouns only.
|
||||
%span.help-block
|
||||
The common name for the crop, in English (required).
|
||||
- if can? :wrangle, @crop
|
||||
Wranglers: please ensure this is singular, and capitalize
|
||||
proper nouns only.
|
||||
|
||||
.form-group
|
||||
= f.label :en_wikipedia_url, 'Wikipedia URL', :class => 'control-label col-md-2'
|
||||
.col-md-8
|
||||
= f.text_field :en_wikipedia_url, :class => 'form-control'
|
||||
%span.help-block Link to this crop's page on the English language Wikipedia.
|
||||
.form-group
|
||||
= f.label :parent_id, 'Parent crop', :class => 'control-label col-md-2'
|
||||
.col-md-8
|
||||
= collection_select(:crop, :parent_id, Crop.all, :id, :name, {:include_blank => true}, :class => 'form-control')
|
||||
%span.help-block Optional. For setting up crop hierarchies for varieties etc.
|
||||
%p
|
||||
%span.help-block
|
||||
You may enter up to 3 scientific names for a crop. Most crops will have only one.
|
||||
%span.help-block
|
||||
Link to the crop's page on the English language Wikipedia (required).
|
||||
|
||||
-# Only crop wranglers see the crop hierarchy (for now)
|
||||
- if can? :wrangle, @crop
|
||||
.form-group
|
||||
= f.label :parent_id, 'Parent crop', :class => 'control-label col-md-2'
|
||||
.col-md-8
|
||||
= collection_select(:crop, :parent_id, Crop.all, :id, :name, {:include_blank => true}, :class => 'form-control')
|
||||
%span.help-block Optional. For setting up crop hierarchies for varieties etc.
|
||||
|
||||
|
||||
-# Everyone (wranglers and requesters) gets to add scientific names
|
||||
%h2 Scientific names
|
||||
%p You may enter up to 3 scientific names for a crop. Most crops will have only one.
|
||||
|
||||
= f.fields_for :scientific_names do |sn|
|
||||
.form-group
|
||||
= sn.label :scientific_name, "Scientific name", :class => 'control-label col-md-2'
|
||||
@@ -40,6 +57,42 @@
|
||||
%label.checkbox
|
||||
= sn.check_box :_destroy
|
||||
= sn.label :_destroy, "Delete"
|
||||
|
||||
-# This is used for comments from crop requesters. We need to show it
|
||||
-# to everyone, but we don't include it on new crops from wranglers.
|
||||
|
||||
- if (can? :wrangle, @crop and @crop.requester) or (cannot? :wrangle, @crop and @crop.new_record?)
|
||||
%h2 Crop request notes
|
||||
.form-group
|
||||
= f.label :request_notes, 'Comments', :class => 'control-label col-md-2'
|
||||
.col-md-8
|
||||
= f.text_area :request_notes, :rows => 3, :class => 'form-control'
|
||||
|
||||
-# A final explanation of what's going to happen next, for crop requesters
|
||||
- unless can? :wrangle, @crop
|
||||
%p When you submit this form, your suggestion will be sent to our team of #{link_to 'volunteer crop wranglers', 'http://talk.growstuff.org/c/crop-wrangling'} for review. We'll let you know the outcome as soon as we can.
|
||||
|
||||
-# Now, for crop wranglers, let's have approval/rejection at the bottom of the page
|
||||
- if can? :wrangle, @crop and @crop.requester
|
||||
%h2 Approve or reject pending crops
|
||||
.form-group
|
||||
= f.label :approval_status, 'Approval status', :class=> 'control-label col-md-2'
|
||||
.col-md-8
|
||||
= f.select(:approval_status, @crop.approval_statuses, {}, {:class => 'form-control'})
|
||||
|
||||
.form-group
|
||||
= f.label :reason_for_rejection, 'Reason for rejection', :class => 'control-label col-md-2'
|
||||
.col-md-8
|
||||
= f.select(:reason_for_rejection, @crop.reasons_for_rejection, {:include_blank => true}, {:class => 'form-control'})
|
||||
|
||||
.form-group
|
||||
= f.label :rejection_notes, 'Rejection notes', :class => 'control-label col-md-2'
|
||||
.col-md-8
|
||||
= f.text_area :rejection_notes, :rows => 3, :class => 'form-control'
|
||||
%span.help-block
|
||||
Please provide additional notes why this crop request was rejected if the above reasons do not apply.
|
||||
|
||||
|
||||
.form-group
|
||||
.form-actions.col-md-offset-2.col-md-8
|
||||
= f.submit 'Save', :class => 'btn btn-primary'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
%h4 Harvests
|
||||
%h4 #{ crop.name.capitalize } harvests
|
||||
- if crop.harvests.empty?
|
||||
%p
|
||||
Nobody has harvested this crop yet.
|
||||
@@ -13,9 +13,9 @@
|
||||
ago.
|
||||
%p
|
||||
= link_to "View all #{crop.name} harvests", harvests_by_crop_path(crop)
|
||||
- if current_member
|
||||
%p
|
||||
= link_to "Harvest #{crop.name}", new_harvest_path(:crop_id => crop.id)
|
||||
- else
|
||||
= render :partial => 'shared/signin_signup', :locals => { :to => "track your #{crop.name} harvests" }
|
||||
- if crop.approved?
|
||||
- if current_member
|
||||
%p= link_to "Harvest #{crop.name}", new_harvest_path(:crop_id => crop.id)
|
||||
- else
|
||||
= render :partial => 'shared/signin_signup', :locals => { :to => "track your #{crop.name} harvests" }
|
||||
|
||||
|
||||
@@ -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', |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
@@ -13,9 +13,9 @@
|
||||
ago.
|
||||
%p
|
||||
= link_to "View all #{crop.name} plantings", plantings_by_crop_path(crop)
|
||||
- if current_member
|
||||
%p
|
||||
= link_to "Plant #{crop.name}", new_planting_path(:crop_id => crop.id)
|
||||
- else
|
||||
= render :partial => 'shared/signin_signup', :locals => { :to => "track your #{crop.name} plantings" }
|
||||
- if crop.approved?
|
||||
- if current_member
|
||||
%p= link_to "Plant #{crop.name}", new_planting_path(:crop_id => crop.id)
|
||||
- else
|
||||
= render :partial => 'shared/signin_signup', :locals => { :to => "track your #{crop.name} plantings" }
|
||||
|
||||
|
||||
@@ -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.crop-name
|
||||
= link_to crop.name, crop
|
||||
- if crop.scientific_names.count > 0
|
||||
%br/
|
||||
%i.scientific-name
|
||||
%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")
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
- content_for :title, "Editing crop"
|
||||
- content_for :title, "Edit crop: #{@crop.name}"
|
||||
|
||||
%p
|
||||
Added by
|
||||
= @crop.creator
|
||||
= distance_of_time_in_words(@crop.created_at, Time.zone.now)
|
||||
ago.
|
||||
- if @crop.approval_status == "approved"
|
||||
- if @crop.requester
|
||||
%p Requested by #{link_to @crop.requester, @crop.requester} #{distance_of_time_in_words(@crop.created_at, Time.zone.now)} ago.
|
||||
%p Approved by #{link_to @crop.creator, @crop.creator}.
|
||||
- else
|
||||
%p Added by #{link_to @crop.creator, @crop.creator} #{distance_of_time_in_words(@crop.created_at, Time.zone.now)} ago.
|
||||
- elsif @crop.approval_status == "pending"
|
||||
.alert.alert-danger
|
||||
%p Requested by #{link_to @crop.requester, @crop.requester} #{distance_of_time_in_words(@crop.created_at, Time.zone.now)} ago.
|
||||
%p Status: #{@crop.approval_status}.
|
||||
- elsif @crop.approval_status == "rejected"
|
||||
.alert.alert-danger
|
||||
%p Requested by #{link_to @crop.requester, @crop.requester} #{distance_of_time_in_words(@crop.created_at, Time.zone.now)} ago.
|
||||
%p Status: #{@crop.approval_status} by #{link_to @crop.creator, @crop.creator}.
|
||||
|
||||
= render 'form'
|
||||
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
- content_for :title, "Crops"
|
||||
- content_for :title, "Browse crops"
|
||||
- content_for :subtitle, "#{@crops.size} total"
|
||||
|
||||
- if can? :wrangle, Crop
|
||||
= link_to 'Wrangle Crops', wrangle_crops_path, :class => 'btn btn-primary'
|
||||
%p
|
||||
#{ENV['GROWSTUFF_SITE_NAME']} tracks who's growing what, where.
|
||||
View any crop page to see which of our members have planted it and find
|
||||
@@ -12,11 +15,10 @@
|
||||
= submit_tag "Show", :class => 'btn btn-primary'
|
||||
|
||||
%div.pagination
|
||||
= page_entries_info @crops, :model => "crops"
|
||||
= will_paginate @crops
|
||||
= will_paginate @paginated_crops
|
||||
|
||||
.row
|
||||
- @crops.each do |crop|
|
||||
- @paginated_crops.each do |crop|
|
||||
.col-md-2.six-across
|
||||
= render :partial => "thumbnail", :locals => { :crop => crop }
|
||||
|
||||
@@ -25,8 +27,7 @@
|
||||
= link_to 'New Crop', new_crop_path, {:class => 'btn btn-primary'}
|
||||
|
||||
%div.pagination
|
||||
= page_entries_info @crops, :model => "crops"
|
||||
= will_paginate @crops
|
||||
= will_paginate @paginated_crops
|
||||
|
||||
|
||||
%ul.list-inline
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
- content_for :title, "New crop"
|
||||
- content_for :title, (can?(:wrangle, @crop) ? "New crop" : "Suggest a crop")
|
||||
|
||||
- unless can? :wrangler, @crop
|
||||
|
||||
%p Thanks for taking the time to suggest a crop! Our crop database is managed by volunteers, and we appreciate your help. Here are some things to consider when suggesting a new crop:
|
||||
|
||||
%ul
|
||||
%li First, you might want to #{link_to 'search our crops', crops_search_path} to make sure we don't have it already, perhaps under an alternate name.
|
||||
|
||||
%li The Growstuff database only contains edible crops. In future we hope to support other crops, but for now, if your suggestion is not edible we won't be able to add it.
|
||||
|
||||
%li At this time, we are only adding crops which have a Wikipedia page. If you want to add a specific variety of crop that doesn't have its own Wikipedia entry, please use the more general form of the crop instead and put the name of your variety in the notes/description.
|
||||
|
||||
= render 'form'
|
||||
|
||||
@@ -1,26 +1,35 @@
|
||||
- content_for :title, "Crops matching #{@search}"
|
||||
- if @term
|
||||
- content_for :title, "Crops matching \"#{@term}\""
|
||||
- if @matches
|
||||
- content_for :subtitle, "#{@matches.size} total"
|
||||
- else
|
||||
- content_for :title, "Crop search"
|
||||
|
||||
- unless (@exact_match || @partial_matches.length > 0)
|
||||
%div
|
||||
= form_tag crops_search_path, :method => :get, :id => 'crop-search', :class => 'form-inline' do
|
||||
.form-group
|
||||
= label_tag :term, "Search crops:", :class => 'sr-only'
|
||||
= text_field_tag 'term', nil, :class => 'search-query input-medium form-control', :placeholder => 'Search crops', :value => @term
|
||||
= submit_tag "Search", :class => 'btn btn-primary'
|
||||
|
||||
- if @matches.empty?
|
||||
%h2 No results found
|
||||
%p
|
||||
Sorry, we couldn't find any crops that matched your search for "#{@search}".
|
||||
Sorry, we couldn't find any crops that matched your search for "#{@term}".
|
||||
%p
|
||||
Try
|
||||
= link_to "browsing our crop database", crops_path
|
||||
instead.
|
||||
|
||||
- if @exact_match
|
||||
%div#exact_match
|
||||
%h2 Exact match
|
||||
- else
|
||||
%div.pagination
|
||||
= will_paginate @paginated_matches
|
||||
|
||||
%div#paginated_matches
|
||||
.row
|
||||
.col-md-2.six-across
|
||||
= render :partial => "thumbnail", :locals => { :crop => @exact_match }
|
||||
|
||||
- if ! @partial_matches.empty?
|
||||
%div#partial_matches
|
||||
%h2 Partial matches
|
||||
.row
|
||||
- @partial_matches.each do |c|
|
||||
- @paginated_matches.each do |c|
|
||||
.col-md-2.six-across
|
||||
= render :partial => "thumbnail", :locals => { :crop => c }
|
||||
|
||||
%div.pagination
|
||||
= will_paginate @paginated_matches
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
- content_for :title, @crop.name
|
||||
- content_for :subtitle, @crop.default_scientific_name
|
||||
- content_for :buttonbar do
|
||||
- if can? :create, Planting
|
||||
= link_to "Plant this", new_planting_path(:crop_id => @crop.id), :class => 'btn btn-default'
|
||||
|
||||
- if can? :create, Harvest
|
||||
= link_to "Harvest this", new_harvest_path(:crop_id => @crop.id), :class => 'btn btn-default'
|
||||
= render :partial => 'approval_status_message', :locals => { :crop => @crop }
|
||||
|
||||
- if can? :create, Seed
|
||||
= link_to 'Add seeds to stash', new_seed_path(:params => { :crop_id => @crop.id }), :class => 'btn btn-default'
|
||||
- if @crop.approved?
|
||||
- content_for :buttonbar do
|
||||
- if can? :create, Planting
|
||||
= link_to "Plant this", new_planting_path(:crop_id => @crop.id), :class => 'btn btn-default'
|
||||
|
||||
- if can? :create, Harvest
|
||||
= link_to "Harvest this", new_harvest_path(:crop_id => @crop.id), :class => 'btn btn-default'
|
||||
|
||||
- if can? :create, Seed
|
||||
= link_to 'Add seeds to stash', new_seed_path(:params => { :crop_id => @crop.id }), :class => 'btn btn-default'
|
||||
|
||||
|
||||
.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,37 +40,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
|
||||
|
||||
= render :partial => 'wrangle', :locals => { :crop => @crop }
|
||||
= render :partial => 'scientific_names', :locals => { :crop => @crop }
|
||||
= render :partial => 'alternate_names', :locals => { :crop => @crop }
|
||||
|
||||
%h4 Planting advice
|
||||
%h4 How to grow #{ @crop.name.pluralize }
|
||||
|
||||
= render :partial => 'grown_for', :locals => { :crop => @crop }
|
||||
= render :partial => 'planting_advice', :locals => { :crop => @crop }
|
||||
|
||||
%h4 Varieties
|
||||
= 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 }
|
||||
|
||||
|
||||
%h4 More information
|
||||
%ul
|
||||
%li= link_to 'Wikipedia (English)', @crop.en_wikipedia_url
|
||||
|
||||
= 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
|
||||
|
||||
@@ -15,28 +15,50 @@
|
||||
%li.crop_wrangler
|
||||
= link_to crop_wrangler.login_name, crop_wrangler
|
||||
|
||||
%h2 Recently added crops
|
||||
.tabbable
|
||||
%ul.nav.nav-tabs
|
||||
%li{:class => @approval_status.blank? ? 'active' : ''}
|
||||
= link_to "Recently added", wrangle_crops_path
|
||||
%li{:class => @approval_status == "pending" ? 'active' : ''}
|
||||
= link_to "Pending approval", wrangle_crops_path(:approval_status => "pending")
|
||||
%li{:class => @approval_status == "rejected" ? 'active' : ''}
|
||||
= link_to "Rejected", wrangle_crops_path(:approval_status => "rejected")
|
||||
|
||||
%h2
|
||||
- if @approval_status == "pending"
|
||||
Requested Crops
|
||||
- elsif @approval_status == "rejected"
|
||||
Rejected Crops
|
||||
- else
|
||||
Recently added crops
|
||||
|
||||
|
||||
%div.pagination
|
||||
= page_entries_info @crops, :model => "crops"
|
||||
= will_paginate @crops
|
||||
|
||||
%table.table.table-striped
|
||||
%table{:class => "table table-striped", :id => @approval_status.blank? ? 'recently-added-crops' : "#{@approval_status}-crops"}
|
||||
%tr
|
||||
%th System name
|
||||
%th English Wikipedia URL
|
||||
%th Scientific names
|
||||
%th Added by
|
||||
%th Requested by
|
||||
- if @approval_status == "rejected"
|
||||
%th Rejected by
|
||||
- if @approval_status != "rejected" && @approval_status != "pending"
|
||||
%th Added by
|
||||
%th When
|
||||
- @crops.each do |c|
|
||||
%tr
|
||||
%td= link_to c.name, c
|
||||
%td= link_to c.name, edit_crop_path(c)
|
||||
%td= link_to c.en_wikipedia_url, c.en_wikipedia_url
|
||||
%td
|
||||
- c.scientific_names.each do |s|
|
||||
= link_to s.scientific_name, s
|
||||
%br/
|
||||
%td= link_to c.creator, c.creator
|
||||
%td= c.requester.present? ? (link_to c.requester, c.requester) : "N/A"
|
||||
- unless @approval_status == "pending"
|
||||
%td= c.creator.present? ? (link_to c.creator, c.creator) : "N/A"
|
||||
%td
|
||||
= distance_of_time_in_words(c.created_at, Time.zone.now)
|
||||
ago.
|
||||
@@ -44,3 +66,5 @@
|
||||
%div.pagination
|
||||
= page_entries_info @crops, :model => "crops"
|
||||
= will_paginate @crops
|
||||
|
||||
|
||||
|
||||
@@ -29,6 +29,21 @@
|
||||
:growstuff_markdown
|
||||
#{strip_tags @garden.description}
|
||||
|
||||
- if @garden.photos.count > 0 or (can? :edit, @garden and can? :create, Photo)
|
||||
.row
|
||||
%h2 Photos
|
||||
|
||||
%ul.thumbnails
|
||||
- @garden.photos.each do |p|
|
||||
.col-md-2.six-across
|
||||
= render :partial => 'photos/thumbnail', :locals => { :photo => p }
|
||||
- if can? :create, Photo and can? :edit, @garden
|
||||
.col-md-2
|
||||
.thumbnail(style='height: 220px')
|
||||
%p{:style => 'text-align: center; padding-top: 50px'}
|
||||
= link_to "Add photo", new_photo_path(:type => "garden", :id => @garden.id), :class => 'btn btn-primary'
|
||||
|
||||
|
||||
%h3
|
||||
What's planted here?
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
= collection_select(:harvest, :plant_part_id, PlantPart.all, :id, :name, { :selected => @harvest.plant_part_id }, { :class => 'form-control' })
|
||||
%span.help-block.col-md-8
|
||||
Can't find what you're looking for?
|
||||
= link_to "Request new crops.", Growstuff::Application.config.new_crops_request_link
|
||||
= link_to "Request new crops.", new_crop_path
|
||||
|
||||
.form-group
|
||||
= f.label :harvested_at, 'When?', :class => 'control-label col-md-2'
|
||||
|
||||
@@ -10,6 +10,7 @@ csv.headers :id,
|
||||
:unit,
|
||||
:weight_quantity,
|
||||
:weight_unit,
|
||||
:si_weight,
|
||||
:date_harvested,
|
||||
:description,
|
||||
:date_added,
|
||||
@@ -31,7 +32,7 @@ csv.headers :id,
|
||||
csv.cell :plant_part_id, h.plant_part ? h.plant_part.id : ''
|
||||
csv.cell :plant_part_name, h.plant_part ? h.plant_part.to_s : ''
|
||||
|
||||
csv.cells :quantity, :unit, :weight_quantity, :weight_unit
|
||||
csv.cells :quantity, :unit, :weight_quantity, :weight_unit, :si_weight
|
||||
|
||||
csv.cell :date_harvested, h.created_at.to_s(:db)
|
||||
|
||||
|
||||
@@ -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')}:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
%h2= t('.keep_in_touch')
|
||||
|
||||
%p
|
||||
= link_to(image_tag("twitter_32.png", :alt => ''), 'http://twitter.com/growstufforg', :target => "_blank")
|
||||
= t('.twitter_html', link: link_to(t('.twitter_linktext'), 'http://twitter.com/growstufforg', :target => "_blank"))
|
||||
|
||||
%p
|
||||
= link_to(image_tag("facebook_32.png", :alt => ''), 'https://www.facebook.com/Growstufforg', :target => "_blank")
|
||||
= t('.facebook_html', link: link_to(t('.facebook_linktext'), 'https://www.facebook.com/Growstufforg', :target => "_blank"))
|
||||
|
||||
%p
|
||||
= link_to(image_tag("blog_32.png", :alt => ''), 'http://blog.growstuff.org/', :target => "_blank")
|
||||
= t('.blog_html', link: link_to(t('.blog_linktext'), 'http://blog.growstuff.org/', :target => "_blank"))
|
||||
|
||||
%p
|
||||
= link_to(image_tag("email_32.png", :alt => ''), 'http://blog.growstuff.org/newsletter', :target => "_blank")
|
||||
= t('.newsletter_html', link: link_to(t('.newsletter_linktext'), 'http://blog.growstuff.org/newsletter', :target => "_blank"))
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user