Compare commits

...

91 Commits

Author SHA1 Message Date
Skud
06b8740f58 Specify ruby version for heroku's benefit 2013-11-23 15:34:42 +11:00
Skud
21c10e09ab upgrade ruby version on heroku due to vulnerability 2013-11-23 15:31:40 +11:00
pozorvlak
23d9229d73 Merge pull request #336 from Skud/quicktweaks
Quick tweaks
2013-10-30 15:46:51 -07:00
Skud
94cb16acbd List inactive gardens separately 2013-10-31 09:29:38 +11:00
Skud
eb8497e1fb Add RSS link to crops index page 2013-10-31 09:25:23 +11:00
Skud
315da26542 Don't show garden location if blank 2013-10-31 09:23:39 +11:00
Skud
26bd744d31 Improve help wording for garden location 2013-10-31 09:18:38 +11:00
pozorvlak
85f132edff Merge pull request #335 from Skud/crop-harvests
Show harvests on crop page
2013-10-29 04:31:27 -07:00
pozorvlak
91e0ba92de Merge pull request #334 from Skud/harvest-bugs
Harvest bugs
2013-10-29 04:31:04 -07:00
Skud
9917b3a489 Show harvests in crop page sidebar
Also tweaked seed display to make them more consistent.
2013-10-29 16:23:17 +11:00
Skud
8dcd3932fa Added a partial to display a member's location. 2013-10-29 16:22:48 +11:00
Skud
0ae0e54369 Sort harvests by created_at DESC 2013-10-29 15:17:01 +11:00
Skud
3494651685 Fixed quantity display bug 2013-10-29 15:02:32 +11:00
Skud
795dc0923f Merge pull request #333 from Skud/garden-inactive
New fields for gardens
2013-10-25 06:45:25 -07:00
Skud
faf0ed39d6 actually this is a slightly better fix 2013-10-26 00:44:30 +11:00
Skud
d49a9e28e4 Fixed broken test 2013-10-26 00:35:38 +11:00
Skud
e26544f5ad Added owner link to the garden page 2013-10-25 23:51:08 +11:00
Skud
b63c854b16 Set default garden locations
Also created a handy rake task to depopulate Null Island (i.e. fix up
anyone's lat/long that's somehow ended up as 0,0).
2013-10-25 23:45:48 +11:00
Skud
86aae6534b Default garden location to the owner's location, if known 2013-10-25 23:25:23 +11:00
Skud
1798696a7b Don't allow planting in inactive gardens 2013-10-25 23:07:48 +11:00
Skud
60392c30ce Only list active gardens in planting form 2013-10-25 23:05:22 +11:00
Skud
dcf5855643 Added new fields to gardens index 2013-10-25 23:01:23 +11:00
Skud
aee0adde43 Added active/inactive scopes 2013-10-25 22:58:40 +11:00
Skud
96b5a6cd94 Added new garden fields to gardens/show 2013-10-25 22:48:02 +11:00
Skud
aee35aeeca Added new fields to garden form 2013-10-25 22:32:40 +11:00
Skud
803f8244c9 Added various fields to garden
- active (default: true)
- location, latitude and longitude (because when you move house, you
    don't take your garden with you)
- area and area units (square feet or metres)
2013-10-25 21:54:13 +11:00
Skud
0aa0c38f1f Removed intentional errors accidentally left in when testing better_errors 2013-10-25 12:34:13 +11:00
Skud
52716df6e9 Fixing up confused crop names from two recent pull requests 2013-10-25 12:26:58 +11:00
Skud
a25ba32476 Merge branch 'system_name_to_name' of https://github.com/pozorvlak/growstuff into pozorvlak-system_name_to_name
Conflicts:
	db/seeds.rb
2013-10-25 12:14:01 +11:00
Skud
22df0a43fd Merge pull request #328 from Skud/crop-csv-upload
Crop csv upload
2013-10-24 18:07:09 -07:00
Skud
3b29efb828 Merge pull request #329 from pozorvlak/better_errors
Turn on better_errors in development.
2013-10-24 18:06:59 -07:00
Skud
f1368d39bb Merge pull request #332 from Skud/rss-links
Added posts and comments RSS links
2013-10-24 18:06:44 -07:00
Skud
2c8f0687e5 Added posts and comments RSS links 2013-10-23 12:06:04 +11:00
Skud
bc03252ffa Merge pull request #331 from Skud/rails_12factor
Added rails_12factor gem to suppress heroku messages
2013-10-21 20:33:54 -07:00
Skud
142df2ebad Added rails_12factor gem to suppress heroku messages 2013-10-22 14:30:05 +11:00
Miles Gould
9c5b6f6192 Rename Crop.system_name to Crop.name 2013-10-18 11:52:05 +01:00
Miles Gould
afa0dbcfa9 Turn on better_errors in development. 2013-10-18 11:03:57 +01:00
Skud
ed01c6fb29 Added some comments/docs to Crop.create_from_csv 2013-10-17 22:49:57 +11:00
Skud
c46e19e43e Load multiple crop CSV files from seeds.rb
We factored out a Crop.create_from_csv method to avoid duplicated code.

Note: naming convention with db/seeds/crop*.csv is to use a 2-digit
number for ordering.  00 and 10 chosen (with a gap in between) because I
learned to program in BASIC and it seemed like a good idea just in case.
2013-10-17 22:45:09 +11:00
Skud
a98cb31161 Added rake task to import new crops from CSV 2013-10-17 22:08:54 +11:00
Skud
bc3a31a6a3 Merge pull request #325 from Skud/csv
Fixed error with blank planting/plant_before dates in CSV files
2013-10-01 19:21:01 -07:00
Skud
219b6e3bbc Merge pull request #326 from Skud/harvests
Harvests
2013-10-01 19:20:43 -07:00
Skud
3f71605572 Turned quick links on homepage into buttons 2013-10-02 10:29:45 +10:00
Skud
7d2cadce83 Added 'harvest this' link to crop page 2013-10-02 10:18:23 +10:00
Skud
97065314f2 Fixed bug in "all test1's seeds" link
and added similar links to plantings and harvests
2013-10-01 12:43:01 +10:00
Skud
294a163918 Removed duplicate edit buttons 2013-10-01 12:37:03 +10:00
Skud
668cb33f15 Added more units for harvests 2013-10-01 12:35:41 +10:00
Skud
233d740df8 Fixed error with blank planting/plant_before dates 2013-10-01 12:21:31 +10:00
pozorvlak
bc6adc8840 Merge pull request #324 from Skud/csv
CSV data dumps
2013-09-27 08:14:12 -07:00
Skud
c23f27e8b0 Added CSV for seeds 2013-09-25 17:15:42 +10:00
Skud
9a48edc187 Fixed erroneous date 2013-09-25 17:12:58 +10:00
Skud
9cf770a200 Adjusted crops.rss to show most recent 2013-09-25 16:59:28 +10:00
Skud
013234c882 Added CSV for plantings 2013-09-25 16:57:27 +10:00
Skud
0116547c96 added links to CSV and JSON data 2013-09-25 16:23:58 +10:00
Skud
9cef31e646 allow per-owner CSV downloads 2013-09-25 16:11:08 +10:00
Skud
c452d38717 If quantity == 0, set it to nil 2013-09-25 16:07:22 +10:00
Skud
92ebf1a43c Added harvest CSV 2013-09-25 16:02:40 +10:00
Skud
1202a48131 Tweaked crop CSV to include added_by and license 2013-09-25 15:51:04 +10:00
Skud
a881ec2250 Merge commit '24255411c9d5907ebb6e8fcb39b6bca1833559d9' into csv 2013-09-25 15:41:47 +10:00
Skud
c5e8e4298f Separated informal/human units from measured weights 2013-09-25 15:39:17 +10:00
Joseph Caudle
00ef1b03d4 Merge pull request #322 from Skud/harvests
Harvests
2013-09-24 16:43:39 -07:00
Skud
4ba7a3a48e added harvest link to signed-in homepage 2013-09-23 10:03:22 +10:00
Skud
c3c3c435d5 improve display of quantities 2013-09-23 10:03:08 +10:00
Skud
9af9d2ac04 Merge pull request #320 from Skud/order_referral_code
Order referral code
2013-09-18 18:16:00 -07:00
Skud
2ee11e19e5 removed spurious puts 2013-09-19 10:57:11 +10:00
Skud
e425a3f7f4 added error message if your referral code has invalid chars 2013-09-19 10:57:00 +10:00
Skud
9667f43874 Added friendly urls to harvests 2013-09-17 18:02:48 +10:00
Skud
c63fc97736 Validate quantity/unit for harvests
If quantity is blank, we also set unit to blank.
2013-09-17 17:56:00 +10:00
Skud
40ce4ab77b Validate units (must be one of individual/bunches/kg/lb)
Also changed "units" attribute to "unit". Oops, we weren't following the
Rails naming convention.
2013-09-17 17:26:18 +10:00
Skud
ebf6034659 Prettified all the harvest views 2013-09-17 17:09:17 +10:00
Skud
ccb0e42c95 Prettified harvest form
Also renamed "notes" to "description" in database
2013-09-17 16:08:41 +10:00
Skud
67b88e8e18 set cancan abilities for harvests 2013-09-17 15:53:51 +10:00
Skud
2196bc8373 Added associations between harvests, crops, and members 2013-09-17 15:51:30 +10:00
Skud
37383ba451 rails g scaffold Harvest... 2013-09-17 15:39:25 +10:00
Skud
3d42e4bce9 Merge pull request #319 from Skud/css-fixes
Css fixes
2013-09-16 17:55:17 -07:00
Skud
4e03e5abbd Merge pull request #318 from Skud/order_referral_code
Order referral code
2013-09-16 00:15:50 -07:00
Skud
24255411c9 added dates created/modified to crops csv 2013-09-16 17:04:39 +10:00
Skud
d014343667 A basic implementation of a CSV dump for crops 2013-09-16 15:33:34 +10:00
Skud
9e374779c0 Fixed navbar display CSS
1) Made sure padding is applied to the body *only* for the larger screen
sizes (by doing so before the responsive CSS is loaded)

2) Fixed indentation on the footer, which was incorrectly putting it
inside the main body container, and thus making it do this weird
narrowing thing at smaller screen sizes.
2013-09-16 11:09:52 +10:00
Skud
df3254135f Made li list style dots more specific
We set all li elements to use list-style disc, but it was affecting our
navbar.  Changed it to use a specific class in the crop hierarchy (where
we actually cared about it).
2013-09-16 10:49:02 +10:00
Skud
ab588bd21b add referral code to order admin table 2013-09-16 10:39:12 +10:00
Skud
a250bc162f Fixed up db/schema to remove spurious payments table 2013-09-16 10:22:42 +10:00
Skud
fef92f0d14 Added tests for admin order controller 2013-09-13 14:19:46 +10:00
Skud
faea1904c2 Added referral code search to admin forms 2013-09-13 13:47:46 +10:00
Skud
1adcedb534 moved admin order search into a model method 2013-09-13 13:38:11 +10:00
Skud
0ce821aacf added referral_code to order form/checkout code 2013-09-13 13:12:11 +10:00
Skud
2422182aa8 Added referral_code to Order
Also added validation (alphanumeric), but we're fairly lax about
whitespace and case, and clean up for them if they make minor errors.
2013-09-13 12:14:17 +10:00
Skud
950a333ac7 Merge pull request #316 from Skud/crop-hierarchy-caching
Added caching of full crop hierarchy
2013-09-12 18:30:15 -07:00
Skud
8994b5f5fc Added caching of full crop hierarchy
... as that page is really slow to load at present.
2013-09-13 11:24:03 +10:00
Skud
dbe542f3d2 Merge pull request #314 from Skud/one-more-places-fix
Removed deploy script reminders, as no longer necessary
2013-09-12 05:06:32 -07:00
Skud
32e49355ff Merge pull request #312 from Skud/one-more-places-fix
removed marker bounds on hover
2013-09-12 04:46:35 -07:00
124 changed files with 2147 additions and 264 deletions

View File

@@ -1,5 +1,7 @@
source 'https://rubygems.org'
ruby "1.9.3"
gem 'bundler', '>=1.1.5'
gem 'rails', '3.2.13'
@@ -14,6 +16,8 @@ gem 'cancan' # for checking member privileges
gem 'gibbon' # for Mailchimp newsletter subscriptions
gem 'csv_shaper' # CSV export
# vendored activemerchant for testing- needed for bogus paypal
# gateway monkeypatch
gem 'activemerchant', '1.33.0',
@@ -27,6 +31,7 @@ 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
@@ -71,6 +76,8 @@ group :development do
# Installation of the debugger gem fails on Travis CI,
# so we don't use it in the test environment
gem 'debugger'
gem 'better_errors'
gem 'binding_of_caller'
end
# Markdown formatting for updates etc

View File

@@ -60,12 +60,18 @@ GEM
multi_json (~> 1.0)
arel (3.0.2)
bcrypt-ruby (3.1.1)
better_errors (1.0.1)
coderay (>= 1.0.0)
erubis (>= 2.6.6)
binding_of_caller (0.7.2)
debug_inspector (>= 0.0.1)
bluecloth (2.2.0)
bootstrap-datepicker-rails (1.1.1.3)
railties (>= 3.0)
builder (3.0.4)
cancan (1.6.10)
chunky_png (1.2.8)
coderay (1.1.0)
coffee-rails (3.2.2)
coffee-script (>= 2.2.0)
railties (~> 3.2.0)
@@ -88,7 +94,10 @@ GEM
rest-client
simplecov (>= 0.7)
thor
csv_shaper (1.0.0)
activesupport (>= 3.0.0)
dalli (2.6.4)
debug_inspector (0.0.2)
debugger (1.6.1)
columnize (>= 0.3.1)
debugger-linecache (~> 1.2.0)
@@ -185,6 +194,11 @@ GEM
activesupport (= 3.2.13)
bundler (~> 1.0)
railties (= 3.2.13)
rails_12factor (0.0.2)
rails_serve_static_assets
rails_stdout_logging
rails_serve_static_assets (0.0.1)
rails_stdout_logging (0.0.3)
railties (3.2.13)
actionpack (= 3.2.13)
activesupport (= 3.2.13)
@@ -253,6 +267,8 @@ PLATFORMS
DEPENDENCIES
active_utils (= 1.0.5)!
activemerchant (= 1.33.0)!
better_errors
binding_of_caller
bluecloth
bootstrap-datepicker-rails
bundler (>= 1.1.5)
@@ -260,6 +276,7 @@ DEPENDENCIES
coffee-rails (~> 3.2.1)
compass-rails (~> 1.0.3)
coveralls
csv_shaper
dalli
debugger
devise
@@ -284,6 +301,7 @@ DEPENDENCIES
pg
rack (~> 1.4.5)
rails (= 3.2.13)
rails_12factor
rake (>= 10.0.0)
rspec-rails (~> 2.12.1)
sass-rails (~> 3.2.3)

View File

@@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/

View File

@@ -1,4 +1,11 @@
@import "twitter/bootstrap/bootstrap";
// this padding needs to be done before the responsive stuff is imported
body {
padding-top: @navbarHeight + 10px;
padding-bottom: @navbarHeight + 10px;
}
@import "twitter/bootstrap/responsive";
// Set the correct sprite paths
@@ -77,10 +84,7 @@
@dropdownLinkColorHover: @brown;
@dropdownLinkBackgroundHover: lighten(@green, 50%);
body {
padding-top: @navbarHeight + 10px;
padding-bottom: @navbarHeight + 10px;
}
ul.inline > li.first {
padding-left: 0px;
}
@@ -151,6 +155,15 @@ p.stats {
height: 500px;
}
.member-location {
font-size: small;
font-style: italic;
}
.member-location a {
color: @brown;
}
// Overrides applying only to mobile view
@media only screen and (max-width: 767px) {
@@ -165,6 +178,6 @@ p.stats {
}
}
li {
li.crop-hierarchy {
list-style-type: disc;
}

View File

@@ -8,34 +8,10 @@ class Admin::OrdersController < ApplicationController
def search
authorize! :manage, :all
@orders = []
@orders = Order.search({:by => params[:search_by], :for => params[:search_text]})
if params[:search_text]
case params[:search_by]
when "member"
member = Member.find_by_login_name(params[:search_text])
if member
@orders = member.orders
end
when "order_id"
order = Order.find_by_id(params[:search_text])
if order
@orders = [order]
end
when "paypal_token"
order = Order.find_by_paypal_express_token(params[:search_text])
if order
@orders = [order]
end
when "paypal_payer_id"
order = Order.find_by_paypal_express_payer_id(params[:search_text])
if order
@orders = [order]
end
end
if @orders.empty?
flash[:alert] = "Couldn't find order with #{params[:search_by]} = #{params[:search_text]}"
end
if @orders.empty?
flash[:alert] = "Couldn't find order with #{params[:search_by]} = #{params[:search_text]}"
end
respond_to do |format|

View File

@@ -10,9 +10,17 @@ class CropsController < ApplicationController
@crops = Crop.includes(:scientific_names, {:plantings => :photos}).paginate(:page => params[:page])
respond_to do |format|
format.html # index.html.haml
format.json { render json: @crops }
format.rss { render :layout => false }
format.html
format.json { render :json => @crops }
format.rss do
@crops = Crop.recent.includes(:scientific_names, :creator)
render :rss => @crops
end
format.csv do
@filename = "Growstuff-Crops-#{Time.zone.now.to_s(:number)}.csv"
@crops = Crop.includes(:scientific_names, :plantings, :seeds, :creator)
render :csv => @crops
end
end
end

View File

@@ -0,0 +1,106 @@
class HarvestsController < ApplicationController
load_and_authorize_resource
# GET /harvests
# GET /harvests.json
def index
@owner = Member.find_by_slug(params[:owner])
if @owner
@harvests = @owner.harvests.includes(:owner, :crop).paginate(:page => params[:page])
else
@harvests = Harvest.includes(:owner, :crop).paginate(:page => params[:page])
end
respond_to do |format|
format.html # index.html.erb
format.json { render json: @harvests }
format.csv do
if @owner
@filename = "Growstuff-#{@owner}-Harvests-#{Time.zone.now.to_s(:number)}.csv"
@harvests = @owner.harvests.includes(:owner, :crop)
else
@filename = "Growstuff-Harvests-#{Time.zone.now.to_s(:number)}.csv"
@harvests = Harvest.includes(:owner, :crop)
end
render :csv => @harvests
end
end
end
# GET /harvests/1
# GET /harvests/1.json
def show
@harvest = Harvest.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: @harvest }
end
end
# GET /harvests/new
# GET /harvests/new.json
def new
@harvest = Harvest.new('harvested_at' => Date.today)
# using find_by_id here because it returns nil, unlike find
@crop = Crop.find_by_id(params[:crop_id]) || Crop.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: @harvest }
end
end
# GET /harvests/1/edit
def edit
@harvest = Harvest.find(params[:id])
end
# POST /harvests
# POST /harvests.json
def create
params[:harvest][:owner_id] = current_member.id
params[:harvested_at] = parse_date(params[:harvested_at])
@harvest = Harvest.new(params[:harvest])
respond_to do |format|
if @harvest.save
format.html { redirect_to @harvest, notice: 'Harvest was successfully created.' }
format.json { render json: @harvest, status: :created, location: @harvest }
else
format.html { render action: "new" }
format.json { render json: @harvest.errors, status: :unprocessable_entity }
end
end
end
# PUT /harvests/1
# PUT /harvests/1.json
def update
@harvest = Harvest.find(params[:id])
respond_to do |format|
if @harvest.update_attributes(params[:harvest])
format.html { redirect_to @harvest, notice: 'Harvest was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: @harvest.errors, status: :unprocessable_entity }
end
end
end
# DELETE /harvests/1
# DELETE /harvests/1.json
def destroy
@harvest = Harvest.find(params[:id])
@harvest.destroy
respond_to do |format|
format.html { redirect_to harvests_url }
format.json { head :no_content }
end
end
end

View File

@@ -32,24 +32,28 @@ class OrdersController < ApplicationController
def checkout
@order = Order.find(params[:id])
response = EXPRESS_GATEWAY.setup_purchase(
@order.total,
:items => @order.activemerchant_items,
:currency => Growstuff::Application.config.currency,
:no_shipping => true,
:ip => request.remote_ip,
:return_url => complete_order_url,
:cancel_return_url => shop_url
)
redirect_to EXPRESS_GATEWAY.redirect_url_for(response.token)
respond_to do |format|
if @order.update_attributes(:referral_code => params[:referral_code])
response = EXPRESS_GATEWAY.setup_purchase(
@order.total,
:items => @order.activemerchant_items,
:currency => Growstuff::Application.config.currency,
:no_shipping => true,
:ip => request.remote_ip,
:return_url => complete_order_url,
:cancel_return_url => shop_url
)
format.html { redirect_to EXPRESS_GATEWAY.redirect_url_for(response.token) }
else
format.html { render action: "show" }
end
end
end
def complete
@order = Order.find(params[:id])
@order.save
if (params[:token] && params['PayerID'])
purchase = EXPRESS_GATEWAY.purchase(
@order.total,

View File

@@ -17,6 +17,16 @@ class PlantingsController < ApplicationController
format.html # index.html.erb
format.json { render json: @plantings }
format.rss { render :layout => false } #index.rss.builder
format.csv do
if @owner
@filename = "Growstuff-#{@owner}-Plantings-#{Time.zone.now.to_s(:number)}.csv"
@plantings = @owner.plantings.includes(:owner, :crop, :garden)
else
@filename = "Growstuff-Plantings-#{Time.zone.now.to_s(:number)}.csv"
@plantings = Planting.includes(:owner, :crop, :garden)
end
render :csv => @plantings
end
end
end

View File

@@ -17,6 +17,16 @@ class SeedsController < ApplicationController
format.html # index.html.erb
format.json { render json: @seeds }
format.rss { render :layout => false } #index.rss.builder
format.csv do
if @owner
@filename = "Growstuff-#{@owner}-Seeds-#{Time.zone.now.to_s(:number)}.csv"
@seeds = @owner.seeds.includes(:owner, :crop)
else
@filename = "Growstuff-Seeds-#{Time.zone.now.to_s(:number)}.csv"
@seeds = Seed.includes(:owner, :crop)
end
render :csv => @seeds
end
end
end

View File

@@ -0,0 +1,40 @@
module HarvestsHelper
def display_quantity(harvest)
human_quantity = display_human_quantity(harvest)
weight = display_weight(harvest)
if human_quantity && weight
return "#{human_quantity}, weighing #{weight}"
elsif human_quantity
return human_quantity
elsif weight
return weight
else
return 'not specified'
end
end
def display_human_quantity(harvest)
if ! harvest.quantity.blank? && harvest.quantity > 0
if harvest.unit == 'individual' # just the number
number_to_human(harvest.quantity, :strip_insignificant_zeros => true)
elsif ! harvest.unit.blank? # pluralize anything else
return pluralize(number_to_human(harvest.quantity, :strip_insignificant_zeros => true), harvest.unit)
else
return "#{number_to_human(harvest.quantity, :strip_insignificant_zeros => true)} #{harvest.unit}"
end
else
return nil
end
end
def display_weight(harvest)
if ! harvest.weight_quantity.blank? && harvest.weight_quantity > 0
return "#{number_to_human(harvest.weight_quantity, :strip_insignificant_zeros => true)} #{harvest.weight_unit}"
else
return nil
end
end
end

View File

@@ -64,6 +64,10 @@ class Ability
can :update, Planting, :garden => { :owner_id => member.id }
can :destroy, Planting, :garden => { :owner_id => member.id }
can :create, Harvest
can :update, Harvest, :owner_id => member.id
can :destroy, Harvest, :owner_id => member.id
can :create, Photo
can :update, Photo, :owner_id => member.id
can :destroy, Photo, :owner_id => member.id

View File

@@ -1,18 +1,19 @@
class Crop < ActiveRecord::Base
extend FriendlyId
friendly_id :system_name, use: :slugged
attr_accessible :en_wikipedia_url, :system_name, :parent_id, :creator_id
friendly_id :name, use: :slugged
attr_accessible :en_wikipedia_url, :name, :parent_id, :creator_id
has_many :scientific_names
has_many :plantings
has_many :photos, :through => :plantings
has_many :seeds
has_many :harvests
belongs_to :creator, :class_name => 'Member'
belongs_to :parent, :class_name => 'Crop'
has_many :varieties, :class_name => 'Crop', :foreign_key => 'parent_id'
default_scope order("lower(system_name) asc")
default_scope order("lower(name) asc")
scope :recent, reorder("created_at desc")
scope :toplevel, where(:parent_id => nil)
scope :randomized, reorder('random()') # ok on sqlite and psql, but not on mysql
@@ -29,7 +30,7 @@ class Crop < ActiveRecord::Base
end
def to_s
return system_name
return name
end
def default_scientific_name
@@ -98,4 +99,52 @@ class Crop < ActiveRecord::Base
return interesting_crops
end
# Crop.create_from_csv(row)
# used by db/seeds.rb and rake growstuff:import_crops
# CSV fields:
# - name (required)
# - scientific name (optional, can be picked up from parent if it has one)
# - en_wikipedia_url (required)
# - parent (name, optional)
def Crop.create_from_csv(row)
name,scientific_name,en_wikipedia_url,parent = row
@cropbot = Member.find_by_login_name('cropbot')
raise "cropbot account not found: run rake db:seed" unless @cropbot
@crop = Crop.find_or_create_by_name(name)
@crop.update_attributes(
:en_wikipedia_url => en_wikipedia_url,
:creator_id => @cropbot.id
)
if parent
@parent = Crop.find_by_name(parent)
if @parent
@crop.update_attributes(:parent_id => @parent.id)
else
logger.warn("Warning: parent crop #{parent} not found")
end
end
unless @crop.scientific_names.exists?(:scientific_name => scientific_name)
@sn = ''
if scientific_name
@sn = scientific_name
elsif @crop.parent
@sn = @crop.parent.scientific_names.first.scientific_name
end
if @sn
@crop.scientific_names.create(
:scientific_name => @sn,
:creator_id => @cropbot.id
)
else
logger.warn("Warning: no scientific name (not even on parent crop) for #{@crop}")
end
end
end
end

View File

@@ -4,6 +4,7 @@ class CropSweeper < ActionController::Caching::Sweeper
def after_create(crop)
expire_fragment('homepage_stats')
expire_fragment('recent_crops')
expire_fragment('full_crop_hierarchy')
end
def after_update(crop)
@@ -13,6 +14,7 @@ class CropSweeper < ActionController::Caching::Sweeper
def after_destroy(crop)
expire_fragment('homepage_stats')
expire_fragment('recent_crops')
expire_fragment('full_crop_hierarchy')
end
end

View File

@@ -1,21 +1,55 @@
class Garden < ActiveRecord::Base
include Geocodable
extend FriendlyId
friendly_id :garden_slug, use: :slugged
attr_accessible :name, :slug, :owner_id, :description
attr_accessible :name, :slug, :owner_id, :description, :active,
:location, :latitude, :longitude, :area, :area_unit
belongs_to :owner, :class_name => 'Member', :foreign_key => 'owner_id'
has_many :plantings, :order => 'created_at DESC', :dependent => :destroy
has_many :crops, :through => :plantings
# before_create :replace_blank_name
# set up geocoding
geocoded_by :location
after_validation :geocode
after_validation :empty_unwanted_geocodes
default_scope order("lower(name) asc")
scope :active, where(:active => true)
scope :inactive, where(:active => false)
validates :name,
:format => {
:with => /\S/
}
validates :area,
:numericality => { :only_integer => false },
:allow_nil => true
AREA_UNITS_VALUES = {
"square metres" => "square metre",
"square feet" => "square foot",
"hectares" => "hectare",
"acres" => "acre"
}
validates :area_unit, :inclusion => { :in => AREA_UNITS_VALUES.values,
:message => "%{value} is not a valid area unit" },
:allow_nil => true,
:allow_blank => true
after_validation :cleanup_area
def cleanup_area
if area == 0
self.area = nil
end
if area.blank?
self.area_unit = nil
end
end
def garden_slug
"#{owner.login_name}-#{name}".downcase.gsub(' ', '-')
end

71
app/models/harvest.rb Normal file
View File

@@ -0,0 +1,71 @@
class Harvest < ActiveRecord::Base
extend FriendlyId
friendly_id :harvest_slug, use: :slugged
attr_accessible :crop_id, :harvested_at, :description, :owner_id,
:quantity, :unit, :weight_quantity, :weight_unit, :slug
belongs_to :crop
belongs_to :owner, :class_name => 'Member'
default_scope order('created_at DESC')
validates :quantity,
:numericality => { :only_integer => false },
:allow_nil => true
UNITS_VALUES = {
"individual" => "individual",
"bunches" => "bunch",
"sprigs" => "sprig",
"handfuls" => "handful",
"litres" => "litre",
"pints" => "ping",
"quarts" => "quart",
"buckets" => "bucket",
"baskets" => "basket",
"bushels" => "bushel"
}
validates :unit, :inclusion => { :in => UNITS_VALUES.values,
:message => "%{value} is not a valid unit" },
:allow_nil => true,
:allow_blank => true
validates :weight_quantity,
:numericality => { :only_integer => false },
:allow_nil => true
WEIGHT_UNITS_VALUES = {
"kg" => "kg",
"lb" => "lb"
}
validates :weight_unit, :inclusion => { :in => WEIGHT_UNITS_VALUES.values,
:message => "%{value} is not a valid unit" },
:allow_nil => true,
:allow_blank => true
after_validation :cleanup_quantities
def cleanup_quantities
if quantity == 0
self.quantity = nil
end
if quantity.blank?
self.unit = nil
end
if weight_quantity == 0
self.weight_quantity = nil
end
if weight_quantity.blank?
self.weight_unit = nil
end
end
def harvest_slug
"#{owner.login_name}-#{crop}".downcase.gsub(' ', '-')
end
end

View File

@@ -1,5 +1,7 @@
class Member < ActiveRecord::Base
include Geocodable
extend FriendlyId
friendly_id :login_name, use: :slugged
has_many :posts, :foreign_key => 'author_id'
@@ -10,6 +12,7 @@ class Member < ActiveRecord::Base
has_many :plantings, :foreign_key => 'owner_id'
has_many :seeds, :foreign_key => 'owner_id'
has_many :harvests, :foreign_key => 'owner_id'
has_and_belongs_to_many :roles
@@ -215,22 +218,6 @@ class Member < ActiveRecord::Base
return nearby_members
end
private
def geocode
unless self.location.blank?
self.latitude, self.longitude =
Geocoder.coordinates(location, params: {limit: 1})
end
end
def empty_unwanted_geocodes
if self.location.blank?
self.latitude = nil
self.longitude = nil
end
end
def update_newsletter_subscription
if confirmed_at_changed? and newsletter # just signed up
newsletter_subscribe

View File

@@ -1,11 +1,18 @@
class Order < ActiveRecord::Base
attr_accessible :member_id, :completed_at
attr_accessible :member_id, :completed_at, :referral_code
belongs_to :member
has_many :order_items, :dependent => :destroy
default_scope order('created_at DESC')
validates :referral_code, :format => {
:with => /\A[a-zA-Z0-9 ]*\z/,
:message => "may only include letters and numbers"
}
before_save :standardize_referral_code
# total price of an order
def total
sum = 0
@@ -45,4 +52,46 @@ class Order < ActiveRecord::Base
end
end
# removes whitespace and forces to uppercase (we're somewhat liberal
# in what we accept, but we clean it up anyway.)
def standardize_referral_code
if referral_code
self.referral_code = referral_code.upcase.gsub /\s/, ''
end
end
# search orders (used by admin/orders)
# usage: Order.search({ :by => 'member', :for => 'Skud' })
# can search by: member, order_id, paypal_token, paypal_payer_id,
def Order.search(args={})
if args[:for]
case args[:by]
when "member"
member = Member.find_by_login_name(args[:for])
if member
return member.orders
end
when "order_id"
order = Order.find_by_id(args[:for])
if order
return [order]
end
when "paypal_token"
order = Order.find_by_paypal_express_token(args[:for])
if order
return [order]
end
when "paypal_payer_id"
order = Order.find_by_paypal_express_payer_id(args[:for])
if order
return [order]
end
when "referral_code"
# coerce to uppercase
return Order.where(:referral_code => args[:for].upcase)
end
end
return []
end
end

View File

@@ -14,7 +14,7 @@ class Planting < ActiveRecord::Base
default_scope order("created_at desc")
delegate :system_name,
delegate :name,
:en_wikipedia_url,
:default_scientific_name,
:plantings_count,
@@ -61,7 +61,7 @@ class Planting < ActiveRecord::Base
# stringify as "beet in Skud's backyard" or similar
def to_s
self.crop_system_name + " in " + self.location
self.crop_name + " in " + self.location
end
def default_photo

View File

@@ -55,6 +55,6 @@ class Seed < ActiveRecord::Base
end
def seed_slug
"#{owner.login_name}-#{crop.system_name}".downcase.gsub(' ', '-')
"#{owner.login_name}-#{crop.name}".downcase.gsub(' ', '-')
end
end

View File

@@ -1,5 +1,5 @@
= form_tag(url_for(:controller => 'admin/orders', :action => 'search'), :method => :get, :class => 'form-inline') do
= label_tag :distance, "Search orders:", :class => 'control-label'
= text_field_tag :search_text
= select_tag :search_by, options_for_select({'Member' => 'member', 'Order ID' => 'order_id', 'Paypal Token' => 'paypal_token', 'Paypal Payer ID' => 'paypal_payer_id' })
= select_tag :search_by, options_for_select({'Member' => 'member', 'Referral code' => 'referral_code', 'Order ID' => 'order_id', 'Paypal Token' => 'paypal_token', 'Paypal Payer ID' => 'paypal_payer_id' })
= submit_tag "Search", :class => 'btn btn-primary'

View File

@@ -12,6 +12,7 @@
%th Member
%th Order number
%th Date completed
%th Referral code
%th Items
%th
@@ -24,6 +25,8 @@
= order.completed_at.to_s
- else
In progress
%td
= order.referral_code
%td
- if order.order_items.count > 0
- order.order_items.each do |o|

View File

@@ -13,3 +13,8 @@
%div.pagination
= page_entries_info @comments, :model => "comments"
= will_paginate @comments
%p
Subscribe to the #{Growstuff::Application.config.site_name}
= succeed "." do
= link_to "comments RSS feed", comments_path(:format => 'rss')

View File

@@ -6,13 +6,8 @@
%ul
- crop.seeds.tradable.each do |seed|
%li
= link_to seed.owner, seed.owner
- if seed.owner.location
in #{seed.owner.location}
- else
(location unknown)
will trade #{seed.tradable_to}.
= link_to "View details.", seed_path(seed)
= link_to "#{seed.owner} will trade #{seed.tradable_to}.", seed_path(seed)
= render :partial => 'members/location', :locals => { :member => seed.owner }
- if current_member
= link_to "List your seeds to trade.", new_seed_path()
- else

View File

@@ -13,9 +13,9 @@
on the Growstuff wiki.
.control-group
= f.label :system_name, :class => 'control-label'
= f.label :name, :class => 'control-label'
.controls
= f.text_field :system_name
= f.text_field :name
%span.help-inline Name in US English; singular; capitalize proper nouns only.
.control-group
= f.label :en_wikipedia_url, 'Wikipedia URL', :class => 'control-label'
@@ -25,7 +25,7 @@
.control-group
= f.label :parent_id, 'Parent crop', :class => 'control-label'
.controls
= collection_select(:crop, :parent_id, Crop.all, :id, :system_name, {:include_blank => true})
= collection_select(:crop, :parent_id, Crop.all, :id, :name, {:include_blank => true})
%span.help-inline Optional. For setting up crop hierarchies for varieties etc.
.form-actions
= f.submit 'Save', :class => 'btn btn-primary'

View File

@@ -0,0 +1,19 @@
%h4 Harvests
- if crop.harvests.empty?
%p
Nobody has harvested this crop yet.
- else
%ul
- crop.harvests.each do |harvest|
%li
= link_to "#{harvest.owner} harvested #{display_quantity(harvest)}.", harvest_path(harvest)
= render :partial => 'members/location', :locals => { :member => harvest.owner }
%small
= distance_of_time_in_words(harvest.created_at, Time.zone.now)
ago.
- if current_member
= link_to "Track your #{crop.name} harvests.", new_harvest_path()
- else
= render :partial => 'shared/signin_signup', :locals => { :to => "track your #{crop.name} harvests" }

View File

@@ -1,6 +1,6 @@
%ul
- display_crops.each do |c|
%li
%li.crop-hierarchy
= link_to c, c
- if c.varieties.present?
- c.varieties.each do |v|

View File

@@ -2,11 +2,11 @@
= link_to |
image_tag( |
crop.default_photo ? crop.default_photo.thumbnail_url : 'placeholder_150.png', |
:alt => crop.system_name |
:alt => crop.name |
), |
crop, |
:rel => "popover", |
'data-trigger' => 'hover', |
'data-title' => crop.system_name, |
'data-title' => crop.name, |
'data-content' => "#{ render :partial => 'crops/popover', :locals => { :crop => crop } }", |
'data-html' => true

View File

@@ -1,8 +1,8 @@
.thumbnail(style='height: 220px')
- if crop
= link_to image_tag((crop.default_photo ? crop.default_photo.thumbnail_url : 'placeholder_150.png'), :alt => crop.system_name, :class => 'img-rounded'), crop
= link_to image_tag((crop.default_photo ? crop.default_photo.thumbnail_url : 'placeholder_150.png'), :alt => crop.name, :class => 'img-rounded'), crop
%p
= link_to crop.system_name, crop
= link_to crop.name, crop
- if crop.scientific_names.count > 0
%br/
%i

View File

@@ -1,6 +1,6 @@
- if crop.parent
%p
= crop.system_name
= crop.name
is a variety of
= succeed "." do
= link_to crop.parent, crop.parent

View File

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

View File

@@ -0,0 +1,83 @@
csv.headers :id, :name,
:growstuff_url, :en_wikipedia_url,
:default_scientific_name,
:scientific_name_count,
:parent_crop_id, :parent_crop_name,
:plantings_count,
:seeds_count,
:recommended_sunniness,
:planted_in_sun,
:planted_in_semi_shade,
:planted_in_shade,
:plant_from_recommendation,
:planted_from_seed,
:planted_from_seedling,
:planted_from_cutting,
:planted_from_root_division,
:planted_from_runner,
:planted_from_bulb,
:planted_from_bare_root_plant,
:planted_from_advanced_plant,
:planted_from_graft,
:planted_from_layering,
:added_by_member_id,
:added_by_member_name,
:date_added,
:last_modified,
:license
@crops.each do |c|
csv.row c do |csv, crop|
csv.cells :id, :name, :en_wikipedia_url
csv.cell :growstuff_url, crop_url(c)
if c.scientific_names.any?
csv.cell :default_scientific_name, c.default_scientific_name
csv.cell :scientific_name_count, c.scientific_names.count
end
if c.parent
csv.cell :parent_crop_id, c.parent.id
csv.cell :parent_crop_name, c.parent.name
end
csv.cell :plantings_count || 0
csv.cell :seeds_count, c.seeds.count
sunniness = c.sunniness
sunniness_rec = sunniness.max_by{|k,v| v}
if sunniness_rec
csv.cell :recommended_sunniness, sunniness_rec[0]
end
csv.cell :planted_in_sun, sunniness['sun']
csv.cell :planted_in_semi_shade, sunniness['semi_shade']
csv.cell :planted_in_shade, sunniness['shade']
planted_from = c.planted_from
planted_from_rec = planted_from.max_by{|k,v| v}
if planted_from_rec
csv.cell :plant_from_recommendation, planted_from_rec[0]
end
csv.cell :planted_from_seed, planted_from['seed']
csv.cell :planted_from_seedling, planted_from['seedling']
csv.cell :planted_from_cutting, planted_from['cutting']
csv.cell :planted_from_root_division, planted_from['root division']
csv.cell :planted_from_runner, planted_from['runner']
csv.cell :planted_from_bulb, planted_from['bulb']
csv.cell :planted_from_bare_root_plant, planted_from['bare root plant']
csv.cell :planted_from_advanced_plant, planted_from['advanced plant']
csv.cell :planted_from_graft, planted_from['graft']
csv.cell :planted_from_layering, planted_from['layering']
csv.cell :added_by_member_id, c.creator.id
csv.cell :added_by_member_name, c.creator.to_s
csv.cell :date_added, c.created_at.to_s(:db)
csv.cell :last_modified, c.updated_at.to_s(:db)
csv.cell :license, "CC-BY-SA Growstuff http://growstuff.org/"
end
end

View File

@@ -22,3 +22,9 @@
= page_entries_info @crops, :model => "crops"
= will_paginate @crops
%ul.inline
%li The data on this page is available in the following formats:
%li= link_to "CSV", crops_path(:format => 'csv')
%li= link_to "JSON", crops_path(:format => 'json')
%li= link_to "RSS", crops_path(:format => 'rss')

View File

@@ -5,7 +5,7 @@
%link= crops_url
- @crops.each do |crop|
%item
%title= crop.system_name
%title= crop.name
%pubDate= crop.created_at.to_s(:rfc822)
%link= post_url(crop)
%guid= post_url(crop)

View File

@@ -1,30 +1,38 @@
- content_for :title, @crop.system_name
- content_for :title, @crop.name
.row-fluid
.span9
= render :partial => 'photos', :locals => { :crop => @crop }
= render :partial => 'varieties', :locals => { :crop => @crop }
= render :partial => 'planting_advice', :locals => { :crop => @crop }
%p
- if @crop.plantings.size > 0
Planted
= pluralize(@crop.plantings.size, "time")
by #{Growstuff::Application.config.site_name} members
- else
Nobody is growing this yet. You could be the first!
%p
- if can? :create, Planting
= link_to "Plant this", new_planting_path(:crop_id => @crop.id), :class => 'btn btn-primary'
- else
= render :partial => 'shared/signin_signup', :locals => { :to => 'plant this crop' }
- if can? :create, Harvest
= link_to "Harvest this", new_harvest_path(:crop_id => @crop.id), :class => 'btn btn-primary'
- if can? :create, Seed
= link_to 'Add seeds to stash', new_seed_path(:params => { :crop_id => @crop.id }), :class => 'btn btn-primary'
= render :partial => 'photos', :locals => { :crop => @crop }
= render :partial => 'varieties', :locals => { :crop => @crop }
= render :partial => 'planting_advice', :locals => { :crop => @crop }
%h2 Who's planted this crop?
%p
- if @crop.plantings.size > 0
= @crop.name.titleize
has been planted
= pluralize(@crop.plantings.size, "time")
by #{Growstuff::Application.config.site_name} members.
- else
Nobody is growing this yet. You could be the first!
- if @crop.plantings.size > 0
- @crop.plantings.each do |p|
= render :partial => "plantings/thumbnail", :locals => { :planting => p, :title => 'owner' }
@@ -59,4 +67,5 @@
%ul
%li= link_to 'Wikipedia (English)', @crop.en_wikipedia_url
= render :partial => 'harvests', :locals => { :crop => @crop }
= render :partial => 'find_seeds', :locals => { :crop => @crop }

View File

@@ -23,7 +23,7 @@
%th When
- @crops.each do |c|
%tr
%td= link_to c.system_name, c
%td= link_to c.name, c
%td= link_to c.en_wikipedia_url, c.en_wikipedia_url
%td
- c.scientific_names.each do |s|

View File

@@ -1,4 +1,4 @@
= form_for @garden, :html => {} do |f|
= form_for(@garden, :html => {:class => "form-horizontal"}) do |f|
- if @garden.errors.any?
#error_explanation
%h2= "#{pluralize(@garden.errors.count, "error")} prohibited this garden from being saved:"
@@ -6,12 +6,41 @@
- @garden.errors.full_messages.each do |msg|
%li= msg
.control_group
= f.label "Garden name: ", :class => 'control-label'
.controls= f.text_field :name
.control-group
= f.label 'Description: ', :class => 'control-label'
.controls= f.text_area :description, :rows => 6
= f.label :name, :class => 'control-label'
.controls
= f.text_field :name
.control-group
= f.label :description, :class => 'control-label'
.controls
= f.text_area :description, :rows => 6
.control-group
= f.label :location, :class => 'control-label'
.controls
= f.text_field :location, :value => @garden.location || current_member.location
%span.help-block
If you have a location set in your profile, it will be used when
you create a new garden.
- if current_member.location.blank?
=link_to "Set your location now.", edit_member_registration_path
- else
=link_to "Change your location.", edit_member_registration_path
.control-group
= f.label :area, :class => 'control-label'
.controls
= f.number_field :area, :class => 'input-small'
= f.select(:area_unit, Garden::AREA_UNITS_VALUES, {:include_blank => false}, :class => 'input-medium')
.control-group
= f.label 'Active? ', :class => 'control-label'
.controls
= f.check_box :active
%span.help-inline
You can mark a garden as inactive if you no longer use it.
.form-actions
= f.submit 'Save Garden', :class => 'btn btn-primary'

View File

@@ -26,6 +26,9 @@
%th Owner
%th Garden name
%th Description
%th Location
%th Area
%th Active?
%th Plantings
%th
@@ -35,6 +38,13 @@
%td= link_to garden.owner.login_name, garden.owner
%td= link_to garden.name, garden
%td= garden.description
%td
- if ! garden.location.blank?
= link_to garden.location, place_path(garden.location)
%td
- if garden.area
= pluralize(garden.area, garden.area_unit)
%td= garden.active ? "Yes" : "No"
%td
- if garden.plantings.empty?
None
@@ -43,7 +53,7 @@
- garden.plantings.each do |p|
%li
= p.quantity
= link_to p.crop.system_name, p
= link_to p.crop.name, p
- if p.planted_at
planted on
= p.planted_at

View File

@@ -1,22 +1,25 @@
=content_for :title, "#{@garden.owner}'s #{@garden}"
.row-fluid
.span3
= render :partial => "members/avatar", :locals => { :member => @garden.owner }
%h4= "#{@garden.owner}'s gardens"
%ul
- @garden.owner.gardens.each do |othergarden|
%li
- if @garden == othergarden
= @garden
- else
= link_to "#{othergarden}", garden_path(othergarden)
- if can? :create, @garden
= link_to 'Add New Garden', new_garden_path, :class => 'btn btn-mini'
.span9
- if ! @garden.active
.alert.alert-notice
NOTE: This garden is inactive.
- if can? :edit, @garden
= link_to 'Set it to active', edit_garden_path(@garden)
to plant something in this garden.
%p
%strong Owner:
= link_to @garden.owner, @garden.owner
- if ! @garden.location.blank?
%p
%strong Location:
= @garden.location
- if ! @garden.area.blank?
%p
%strong Area:
= pluralize(@garden.area, @garden.area_unit)
%div
:markdown
#{strip_tags @garden.description}
@@ -28,9 +31,30 @@
%h3
What's planted here?
- if can? :edit, @garden
- if can? :edit, @garden and @garden.active
= link_to "Plant something", new_planting_path(:garden_id => @garden.id), :class => 'btn btn-primary'
- @garden.plantings.each do |p|
= render :partial => "plantings/thumbnail", :locals => { :planting => p }
.span3
%h4= "#{@garden.owner}'s gardens"
%ul
- @garden.owner.gardens.active.each do |othergarden|
%li
- if @garden == othergarden
= @garden
- else
= link_to "#{othergarden}", garden_path(othergarden)
%h4= "Inactive gardens"
%ul
- @garden.owner.gardens.inactive.each do |othergarden|
%li
- if @garden == othergarden
= @garden
- else
= link_to "#{othergarden}", garden_path(othergarden)
- if can? :create, @garden
= link_to 'Add New Garden', new_garden_path, :class => 'btn btn-mini'

View File

@@ -0,0 +1,39 @@
= form_for(@harvest, :html => {:class => "form-horizontal"}) do |f|
- if @harvest.errors.any?
#error_explanation
%h2= "#{pluralize(@harvest.errors.count, "error")} prohibited this harvest from being saved:"
%ul
- @harvest.errors.full_messages.each do |msg|
%li= msg
.control-group
= f.label 'What did you harvest?', :class => 'control-label'
.controls
= collection_select(:harvest, :crop_id, Crop.all, :id, :name, :selected => @harvest.crop_id || @crop.id)
%span.help-inline
Can't find what you're looking for?
= link_to "Request new crops.", Growstuff::Application.config.new_crops_request_link
.control-group
= f.label 'When?', :class => 'control-label'
.controls= f.text_field :harvested_at, :value => @harvest.harvested_at ? @harvest.harvested_at.to_s(:ymd) : '', :class => 'add-datepicker'
.control-group
= f.label 'How many?', :class => 'control-label'
.controls
= f.number_field :quantity, :class => 'input-small'
= f.select(:unit, Harvest::UNITS_VALUES, {:include_blank => false}, :class => 'input-medium')
.control-group
= f.label 'Weighing:', :class => 'control-label'
.controls
= f.number_field :weight_quantity, :class => 'input-small'
= f.select(:weight_unit, Harvest::WEIGHT_UNITS_VALUES, {:include_blank => false}, :class => 'input-medium')
in total
.control-group
= f.label 'Notes', :class => 'control-label'
.controls= f.text_area :description, :rows => 6
.form-actions
= f.submit 'Save', :class => 'btn btn-primary'

View File

@@ -0,0 +1,7 @@
- content_for :title, "Editing harvest"
= render 'form'
= link_to 'Show', @harvest
\|
= link_to 'Back', harvests_path

View File

@@ -0,0 +1,41 @@
csv.headers :id,
:growstuff_url,
:owner_id,
:owner_name,
:crop_id,
:crop_name,
:quantity,
:unit,
:weight_quantity,
:weight_unit,
:date_harvested,
:description,
:date_added,
:last_modified,
:license
@harvests.each do |h|
csv.row h do |csv, harvest|
csv.cell :id
csv.cell :growstuff_url, harvest_url(h)
csv.cell :owner_id, h.owner.id
csv.cell :owner_name, h.owner.to_s
csv.cell :crop_id, h.crop.id
csv.cell :crop_name, h.crop.to_s
csv.cells :quantity, :unit, :weight_quantity, :weight_unit
csv.cell :date_harvested, h.created_at.to_s(:db)
csv.cell :description
csv.cell :date_added, h.created_at.to_s(:db)
csv.cell :last_modified, h.updated_at.to_s(:db)
csv.cell :license, "CC-BY-SA Growstuff http://growstuff.org/"
end
end

View File

@@ -0,0 +1,58 @@
- content_for :title, @owner ? "#{@owner}'s harvests" : "Everyone's harvests"
%p
#{Growstuff::Application.config.site_name} helps you track what you're
harvesting from your home garden and see how productive it is.
%p
- if can? :create, Harvest
- if @owner
%p
- if @owner == current_member
= link_to 'Add harvest', new_harvest_path, :class => 'btn btn-primary'
= link_to "View everyone's harvests", harvests_path, :class => 'btn'
- else # everyone's harvests
= link_to 'Add harvest', new_harvest_path, :class => 'btn btn-primary'
- if current_member
= link_to 'View your harvests', harvests_by_owner_path(:owner => current_member.slug), :class => 'btn'
- else
= render :partial => 'shared/signin_signup', :locals => { :to => 'track your harvests' }
%div.pagination
= page_entries_info @harvests, :model => "harvests"
= will_paginate @harvests
- if @harvests.length > 0
%table.table.table-striped
%tr
- unless @owner
%th Owner
%th Crop
%th Date
%th Quantity
%th Description
%th
- @harvests.each do |harvest|
%tr
- unless @owner
%td= link_to harvest.owner.login_name, harvest.owner
%td= link_to harvest.crop.name, harvest.crop
%td= harvest.harvested_at
%td= display_quantity(harvest)
%td= harvest.description
%td= link_to 'Details', harvest, :class => 'btn btn-mini'
%div.pagination
= page_entries_info @harvests, :model => "harvests"
= will_paginate @harvests
%ul.inline
%li The data on this page is available in the following formats:
- if @owner
%li= link_to "CSV", harvests_by_owner_path(@owner, :format => 'csv')
%li= link_to "JSON", harvests_by_owner_path(@owner, :format => 'json')
- else
%li= link_to "CSV", harvests_path(:format => 'csv')
%li= link_to "JSON", harvests_path(:format => 'json')

View File

@@ -0,0 +1,3 @@
- content_for :title, "New Harvest"
= render 'form'

View File

@@ -0,0 +1,30 @@
=content_for :title, "#{@harvest.crop} harvested by #{@harvest.owner}"
.row-fluid
.span6
%p
%b Owner:
= link_to @harvest.owner, @harvest.owner
&mdash;
= link_to "view all #{@harvest.owner}'s harvests", harvests_by_owner_path(:owner => @harvest.owner.slug)
%p
%b Harvested:
= @harvest.harvested_at ? @harvest.harvested_at : "not specified"
%p
%b Quantity:
= display_quantity(@harvest)
- if can? :edit, @harvest or can? :destroy, @harvest
%p
- if can? :edit, @harvest
=link_to 'Edit', edit_harvest_path(@harvest), :class => 'btn btn-mini'
- if can? :destroy, @harvest
=link_to 'Delete', @harvest, method: :delete, data: { confirm: 'Are you sure?' }, :class => 'btn btn-mini'
.span6
= render :partial => "crops/index_card", :locals => { :crop => @harvest.crop}
%h2 Notes
:markdown
#{ @harvest.description != "" ? @harvest.description : "No description given." }

View File

@@ -18,7 +18,7 @@
- seeds.each do |seed|
%tr
%td= link_to seed.owner.login_name, seed.owner
%td= link_to seed.crop.system_name, seed.crop
%td= link_to seed.crop.name, seed.crop
%td.hidden-phone.hidden-tablet= truncate(seed.description, :length => 40, :separator => ' ')
%td= seed.tradable? ? seed.tradable_to : ''
%td

View File

@@ -7,13 +7,13 @@
= Growstuff::Application.config.site_name
= current_member
= render :partial => 'stats'
%ul.inline
%li{ :style => 'padding-left: 0px' }
%strong Quick links:
%li= link_to "Plant something", new_planting_path
%li= link_to "Add seeds", new_seed_path
%li= link_to "Post", new_post_path
%li= link_to "Edit profile", edit_member_registration_path
%p
.btn-group
= link_to "Plant", new_planting_path, :class => 'btn'
= link_to "Harvest", new_harvest_path, :class => 'btn'
= link_to "Add seeds", new_seed_path, :class => 'btn'
= link_to "Post", new_post_path, :class => 'btn'
= link_to "Edit profile", edit_member_registration_path, :class => 'btn'
- else
.visible-desktop.visible-tablet

View File

@@ -1,12 +1,11 @@
.container
.navbar.navbar-fixed-bottom
.navbar-inner
.container
%ul.nav
%li= link_to "About", "http://wiki.growstuff.org/index.php/About%20Growstuff"
%li= link_to "Contact", url_for(:controller => '/about', :action => 'contact')
%li= link_to "Terms of Service", url_for(:controller => '/policy', :action => 'tos')
%li= link_to "Privacy Policy", url_for(:controller => %'/policy', :action => 'privacy')
%li= link_to "Community Guidelines", url_for(:controller => '/policy', :action => 'community')
%li= link_to "Support/FAQ", url_for(:controller => '/support')
%li= link_to "Open Source", "https://github.com/Growstuff/growstuff"
.navbar.navbar-fixed-bottom
.navbar-inner
.container
%ul.nav
%li= link_to "About", "http://wiki.growstuff.org/index.php/About%20Growstuff"
%li= link_to "Contact", url_for(:controller => '/about', :action => 'contact')
%li= link_to "Terms of Service", url_for(:controller => '/policy', :action => 'tos')
%li= link_to "Privacy Policy", url_for(:controller => %'/policy', :action => 'privacy')
%li= link_to "Community Guidelines", url_for(:controller => '/policy', :action => 'community')
%li= link_to "Support/FAQ", url_for(:controller => '/support')
%li= link_to "Open Source", "https://github.com/Growstuff/growstuff"

View File

@@ -34,6 +34,7 @@
%li= link_to "Profile", member_path(current_member)
%li= link_to "Gardens", gardens_by_owner_path(:owner => current_member.slug)
%li= link_to "Plantings", plantings_by_owner_path(:owner => current_member.slug)
%li= link_to "Harvests", harvests_by_owner_path(:owner => current_member.slug)
%li= link_to "Seeds", seeds_by_owner_path(:owner => current_member.slug)
%li= link_to "Posts", posts_by_author_path(:author => current_member.slug)
%li= link_to "Account", orders_path

View File

@@ -17,8 +17,8 @@
= alert
= yield
%footer
= render :partial => "layouts/footer"
%footer
= render :partial => "layouts/footer"
/
Javascripts
\==================================================

View File

@@ -0,0 +1,5 @@
.member-location
- if member.location.blank?
unknown location
- else
= link_to member.location, place_path(:place => member.location)

View File

@@ -14,4 +14,4 @@
%small
%br/
Recently planted:
!= member.plantings.first(3).map{|p| link_to p.crop_system_name, p }.join(", ")
!= member.plantings.first(3).map{|p| link_to p.crop_name, p }.join(", ")

View File

@@ -12,18 +12,23 @@
%strong Date begun:
= @order.created_at.to_s
%p
- if @order.completed_at
- if @order.completed_at
%p
%strong Date completed:
= @order.completed_at.to_s
- if current_member.has_role? :admin
%p
%strong Paypal Express token:
= @order.paypal_express_token
%p
%strong Paypal Express payer ID:
= @order.paypal_express_payer_id
- if @order.referral_code
%p
%strong Referral code:
= @order.referral_code
- if current_member.has_role? :admin
%p
%strong Paypal Express token:
= @order.paypal_express_token
%p
%strong Paypal Express payer ID:
= @order.paypal_express_payer_id
%h2 Order items
@@ -53,12 +58,24 @@
= price_with_currency(@order.total)
= forex_link(@order.total)
%p
- if can? :destroy, @order
= link_to 'Delete this order', @order, method: :delete, |
data: { confirm: 'Are you sure?' }, :class => 'btn'
- if can? :complete, @order
= link_to 'Checkout with PayPal', checkout_order_path(@order), :class => 'btn btn-primary'
- if @order.errors.any?
.alert
#error_explanation
%h3= "#{pluralize(@order.errors.count, "error")} stopped you from checking out:"
%ul
- @order.errors.full_messages.each do |msg|
%li= msg
- if can? :complete, @order or can? :destroy, @order
= form_tag(checkout_order_path(@order), :method => :get, :class => 'form-inline') do
%p
- if can? :complete, @order
= label_tag :referral_code, "Do you have a referral code?"
= text_field_tag :referral_code, @order.referral_code, :class => 'input-medium'
= submit_tag "Checkout with PayPal", :class => 'btn btn-primary'
- if can? :destroy, @order
= link_to 'Delete this order', @order, method: :delete, |
data: { confirm: 'Are you sure?' }, :class => 'btn'
= link_to "View other orders/order history", orders_path, :class => 'btn'
%p
= link_to "View other orders/order history", orders_path

View File

@@ -9,14 +9,14 @@
.control-group
= f.label 'What did you plant?', :class => 'control-label'
.controls
= collection_select(:planting, :crop_id, Crop.all, :id, :system_name, :selected => @planting.crop_id || @crop.id)
= collection_select(:planting, :crop_id, Crop.all, :id, :name, :selected => @planting.crop_id || @crop.id)
%span.help-inline
Can't find what you're looking for?
= link_to "Request new crops.", Growstuff::Application.config.new_crops_request_link
.control-group
= f.label 'Where did you plant it?', :class => 'control-label'
.controls
= collection_select(:planting, :garden_id, Garden.where(:owner_id => current_member), :id, :name, :selected => @planting.garden_id || @garden.id)
= collection_select(:planting, :garden_id, Garden.active.where(:owner_id => current_member), :id, :name, :selected => @planting.garden_id || @garden.id)
%span.help-inline
= link_to "Add a garden.", new_garden_path
.control-group

View File

@@ -8,7 +8,7 @@
- if defined?(title) && title == 'owner'
= link_to planting.owner, planting.owner
- else
= link_to planting.crop.system_name, planting
= link_to planting.crop.name, planting
%p
Planted

View File

@@ -0,0 +1,45 @@
csv.headers :id,
:growstuff_url,
:owner_id,
:owner_name,
:garden_id,
:garden_name,
:crop_id,
:crop_name,
:quantity,
:planted_from,
:sunniness,
:date_planted,
:description,
:date_added,
:last_modified,
:license
@plantings.each do |p|
csv.row p do |csv, planting|
csv.cell :id
csv.cell :growstuff_url, planting_url(p)
csv.cell :owner_id, p.owner.id
csv.cell :owner_name, p.owner.to_s
csv.cell :garden_id, p.garden.id
csv.cell :garden_name, p.garden.to_s
csv.cell :crop_id, p.crop.id
csv.cell :crop_name, p.crop.to_s
csv.cells :quantity, :planted_from, :sunniness
csv.cell :date_planted, p.planted_at ? p.planted_at.to_s(:db) : ''
csv.cell :description
csv.cell :date_added, p.created_at.to_s(:db)
csv.cell :last_modified, p.updated_at.to_s(:db)
csv.cell :license, "CC-BY-SA Growstuff http://growstuff.org/"
end
end

View File

@@ -37,7 +37,7 @@
%tr
- unless @owner
%td= link_to planting.owner.login_name, planting.owner
%td= link_to planting.crop.system_name, planting.crop
%td= link_to planting.crop.name, planting.crop
%td= link_to planting.garden.name, planting.garden
%td
:markdown
@@ -51,3 +51,14 @@
%div.pagination
= page_entries_info @plantings, :model => "plantings"
= will_paginate @plantings
%ul.inline
%li The data on this page is available in the following formats:
- if @owner
%li= link_to "CSV", plantings_by_owner_path(@owner, :format => 'csv')
%li= link_to "JSON", plantings_by_owner_path(@owner, :format => 'json')
%li= link_to "RSS", plantings_by_owner_path(@owner, :format => 'rss')
- else
%li= link_to "CSV", plantings_path(:format => 'csv')
%li= link_to "JSON", plantings_path(:format => 'json')
%li= link_to "RSS", plantings_path(:format => 'rss')

View File

@@ -2,6 +2,11 @@
.row-fluid
.span6
%p
%b Owner:
= link_to @planting.owner, @planting.owner
&mdash;
= link_to "view all #{@planting.owner}'s plantings", plantings_by_owner_path(:owner => @planting.owner.slug)
%p
%b Planted:
= @planting.planted_at ? @planting.planted_at : "not specified"
@@ -41,9 +46,6 @@
:markdown
#{ @planting.description != "" ? @planting.description : "No description given." }
- if can? :edit, @planting
= link_to 'Edit', edit_planting_path(@planting), :class => 'btn btn-mini'
- if @planting.photos.count > 0 or (can? :edit, @planting and can? :create, Photo)
%h2 Pictures

View File

@@ -25,3 +25,16 @@
%div.pagination
= page_entries_info @posts, :model => "posts"
= will_paginate @posts
%p
- if @author
Subscribe to
= succeed "." do
= link_to "#{@author}'s posts RSS feed", posts_path(:format => 'rss')
- else
Subscribe to the #{Growstuff::Application.config.site_name}
= link_to "posts RSS feed", posts_path(:format => 'rss')
or
= succeed "." do
= link_to "comments RSS feed", comments_path(:format => 'rss')

View File

@@ -15,7 +15,7 @@
.control-group
= f.label :crop_id, :class => 'control-label'
.controls
= collection_select(:scientific_name, :crop_id, Crop.all, :id, :system_name, :selected => @scientific_name.crop_id || @crop.id)
= collection_select(:scientific_name, :crop_id, Crop.all, :id, :name, :selected => @scientific_name.crop_id || @crop.id)
.control-group
= f.label :scientific_name, :class => 'control-label'
.controls

View File

@@ -8,7 +8,7 @@
.control-group
= f.label 'Crop:', :class => 'control-label'
.controls= collection_select(:seed, :crop_id, Crop.all, :id, :system_name, :selected => @seed.crop_id || @crop.id)
.controls= collection_select(:seed, :crop_id, Crop.all, :id, :name, :selected => @seed.crop_id || @crop.id)
.control-group
= f.label 'Quantity:', :class => 'control-label'
.controls

View File

@@ -0,0 +1,47 @@
csv.headers :id,
:growstuff_url,
:owner_id,
:owner_name,
:crop_id,
:crop_name,
:quantity,
:plant_before,
:tradable_to,
:from_location,
:latitude,
:longitude,
:description,
:date_added,
:last_modified,
:license
@seeds.each do |s|
csv.row s do |csv, seed|
csv.cell :id
csv.cell :growstuff_url, seed_url(s)
csv.cell :owner_id, s.owner.id
csv.cell :owner_name, s.owner.to_s
csv.cell :crop_id, s.crop.id
csv.cell :crop_name, s.crop.to_s
csv.cell :quantity
csv.cell :plant_before, s.plant_before ? s.plant_before.to_s(:db) : ''
csv.cell :tradable_to
csv.cell :from_location, s.owner.location
csv.cell :latitude, s.owner.latitude
csv.cell :longitude, s.owner.longitude
csv.cell :description
csv.cell :date_added, s.created_at.to_s(:db)
csv.cell :last_modified, s.updated_at.to_s(:db)
csv.cell :license, "CC-BY-SA Growstuff http://growstuff.org/"
end
end

View File

@@ -40,7 +40,7 @@
%tr
- unless @owner
%td= link_to seed.owner.login_name, seed.owner
%td= link_to seed.crop.system_name, seed.crop
%td= link_to seed.crop.name, seed.crop
%td= seed.description
%td= seed.quantity
%td= seed.plant_before
@@ -56,3 +56,14 @@
%div.pagination
= page_entries_info @seeds, :model => "seeds"
= will_paginate @seeds
%ul.inline
%li The data on this page is available in the following formats:
- if @owner
%li= link_to "CSV", seeds_by_owner_path(@owner, :format => 'csv')
%li= link_to "JSON", seeds_by_owner_path(@owner, :format => 'json')
%li= link_to "RSS", seeds_by_owner_path(@owner, :format => 'rss')
- else
%li= link_to "CSV", seeds_path(:format => 'csv')
%li= link_to "JSON", seeds_path(:format => 'json')
%li= link_to "RSS", seeds_path(:format => 'rss')

View File

@@ -6,7 +6,7 @@
%b Owner:
= link_to @seed.owner, @seed.owner
&mdash;
= link_to "view all #{@seed.owner}'s seeds", seeds_path(:owner_id => @seed.owner.id)
= link_to "view all #{@seed.owner}'s seeds", seeds_by_owner_path(:owner => @seed.owner.slug)
%p
%b Quantity:
= @seed.quantity.blank? ? "not specified" : @seed.quantity

View File

@@ -1,3 +1,5 @@
require 'geocodable'
Geocoder.configure(
:units => :km,
:timeout => 10,

View File

@@ -13,3 +13,7 @@
# ActiveSupport::Inflector.inflections do |inflect|
# inflect.acronym 'RESTful'
# end
ActiveSupport::Inflector.inflections do |inflect|
inflect.plural 'square foot', 'square feet'
end

View File

@@ -16,6 +16,9 @@ Growstuff::Application.routes.draw do
resources :seeds
match '/seeds/owner/:owner' => 'seeds#index', :as => 'seeds_by_owner'
resources :harvests
match '/harvests/owner/:owner' => 'harvests#index', :as => 'harvests_by_owner'
resources :posts
match '/posts/author/:author' => 'posts#index', :as => 'posts_by_author'

View File

@@ -0,0 +1,5 @@
class AddReferralCodeToOrder < ActiveRecord::Migration
def change
add_column :orders, :referral_code, :string
end
end

View File

@@ -0,0 +1,14 @@
class CreateHarvests < ActiveRecord::Migration
def change
create_table :harvests do |t|
t.integer :crop_id, :null => false
t.integer :owner_id, :null => false
t.date :harvested_at
t.decimal :quantity
t.string :units
t.text :notes
t.timestamps
end
end
end

View File

@@ -0,0 +1,5 @@
class ChangeHarvestNotesToDescription < ActiveRecord::Migration
def change
rename_column :harvests, :notes, :description
end
end

View File

@@ -0,0 +1,5 @@
class ChangeHarvestUnitsToUnit < ActiveRecord::Migration
def change
rename_column :harvests, :units, :unit
end
end

View File

@@ -0,0 +1,5 @@
class AddSlugToHarvests < ActiveRecord::Migration
def change
add_column :harvests, :slug, :string
end
end

View File

@@ -0,0 +1,6 @@
class AddWeightToHarvests < ActiveRecord::Migration
def change
add_column :harvests, :weight_quantity, :decimal
add_column :harvests, :weight_unit, :string
end
end

View File

@@ -0,0 +1,15 @@
class RenameSystemNameToName < ActiveRecord::Migration
def up
# Rails is smart enough to alter the column being indexed, but not the name
# of the index, and there's no rename_index command.
remove_index :crops, :system_name
rename_column :crops, :system_name, :name
add_index :crops, :name
end
def down
remove_index :crops, :name
rename_column :crops, :name, :system_name
add_index :crops, :system_name
end
end

View File

@@ -0,0 +1,10 @@
class AddFieldsToGardens < ActiveRecord::Migration
def change
add_column :gardens, :active, :boolean, :default => true
add_column :gardens, :location, :string
add_column :gardens, :latitude, :float
add_column :gardens, :longitude, :float
add_column :gardens, :area, :decimal
add_column :gardens, :area_unit, :string
end
end

View File

@@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20130827105823) do
ActiveRecord::Schema.define(:version => 20131025104228) do
create_table "account_types", :force => true do |t|
t.string "name", :null => false
@@ -51,7 +51,7 @@ ActiveRecord::Schema.define(:version => 20130827105823) do
end
create_table "crops", :force => true do |t|
t.string "system_name", :null => false
t.string "name", :null => false
t.string "en_wikipedia_url"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
@@ -61,8 +61,8 @@ ActiveRecord::Schema.define(:version => 20130827105823) do
t.integer "creator_id"
end
add_index "crops", ["name"], :name => "index_crops_on_name"
add_index "crops", ["slug"], :name => "index_crops_on_slug", :unique => true
add_index "crops", ["system_name"], :name => "index_crops_on_system_name"
create_table "forums", :force => true do |t|
t.string "name", :null => false
@@ -76,17 +76,37 @@ ActiveRecord::Schema.define(:version => 20130827105823) do
add_index "forums", ["slug"], :name => "index_forums_on_slug", :unique => true
create_table "gardens", :force => true do |t|
t.string "name", :null => false
t.string "name", :null => false
t.integer "owner_id"
t.string "slug", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "slug", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.text "description"
t.boolean "active", :default => true
t.string "location"
t.float "latitude"
t.float "longitude"
t.decimal "area"
t.string "area_unit"
end
add_index "gardens", ["owner_id"], :name => "index_gardens_on_user_id"
add_index "gardens", ["slug"], :name => "index_gardens_on_slug", :unique => true
create_table "harvests", :force => true do |t|
t.integer "crop_id", :null => false
t.integer "owner_id", :null => false
t.date "harvested_at"
t.decimal "quantity"
t.string "unit"
t.text "description"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "slug"
t.decimal "weight_quantity"
t.string "weight_unit"
end
create_table "members", :force => true do |t|
t.string "email", :default => "", :null => false
t.string "encrypted_password", :default => "", :null => false
@@ -158,6 +178,7 @@ ActiveRecord::Schema.define(:version => 20130827105823) do
t.integer "member_id"
t.string "paypal_express_token"
t.string "paypal_express_payer_id"
t.string "referral_code"
end
create_table "orders_products", :id => false, :force => true do |t|
@@ -165,14 +186,6 @@ ActiveRecord::Schema.define(:version => 20130827105823) do
t.integer "product_id"
end
create_table "payments", :force => true do |t|
t.integer "payer_id"
t.string "payment_type"
t.decimal "amount"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "photos", :force => true do |t|
t.integer "owner_id", :null => false
t.string "thumbnail_url", :null => false

View File

@@ -1,12 +1,5 @@
# This file should contain all the record creation needed to seed the database with its default values.
# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
#
# Examples:
#
# cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }])
# Mayor.create(name: 'Emanuel', city: cities.first)
# import crops from CSV
require 'csv'
@@ -29,18 +22,12 @@ def load_data
end
def load_crops
puts "Loading crops..."
CSV.foreach(Rails.root.join('db', 'seeds', 'crops.csv')) do |row|
system_name,scientific_name,en_wikipedia_url = row
@crop = Crop.create(
:system_name => system_name,
:en_wikipedia_url => en_wikipedia_url,
:creator_id => @cropbot_user.id
)
@crop.scientific_names.create(
:scientific_name => scientific_name,
:creator_id => @cropbot_user.id
)
source_path = Rails.root.join('db', 'seeds')
Dir.glob("#{source_path}/crops*.csv").each do |crop_file|
puts "Loading crops from #{crop_file}..."
CSV.foreach(crop_file) do |row|
Crop.create_from_csv(row)
end
end
puts "Finished loading crops"
end

View File

@@ -0,0 +1,61 @@
Capsicum,Capsicum,http://en.wikipedia.org/wiki/Capsicum,,This is the top parent variety -- the entire family of all kinds of peppers
Capsicum annuum,Capsicum annuum,http://en.wikipedia.org/wiki/Capsicum_annuum,Capsicum,
Capsicum baccatum,Capsicum baccatum,http://en.wikipedia.org/wiki/Capsicum_baccatum,Capsicum,
Capsicum chinense,Capsicum chinense,http://en.wikipedia.org/wiki/Capsicum_chinense,Capsicum,
rocoto,Capsicum pubescens,http://en.wikipedia.org/wiki/Capsicum_pubescens,Capsicum,AKA locoto
Capsicum frutescens,Capsicum frutescens,http://en.wikipedia.org/wiki/Capsicum_frutescens,Capsicum,
Aleppo pepper,,http://en.wikipedia.org/wiki/Aleppo_pepper,Capsicum annuum,"AKA pul biber, halaby pepper"
Anaheim pepper,,http://en.wikipedia.org/wiki/Anaheim_pepper,Capsicum annuum,"AKA New Mexico pepper, California chili, Magdalena chili"
banana pepper,,http://en.wikipedia.org/wiki/Banana_pepper,Capsicum annuum,"AKA yellow wax pepper, banana chili"
bell pepper,,http://en.wikipedia.org/wiki/Bell_pepper,Capsicum annuum,"AKA capsicum, sweet pepper, pepper, poivron, peperoni, piment"
bird's eye chili,,http://en.wikipedia.org/wiki/Bird%27s_eye_chili,Capsicum annuum,"AKA Thai chili pepper, bird's chili"
cascabel chili,,http://en.wikipedia.org/wiki/Cascabel_chili,Capsicum annuum,"AKA rattle chile, bola chile, chile bola"
cayenne pepper,,http://en.wikipedia.org/wiki/Cayenne_pepper,Capsicum annuum,"AKA Guinea spice, cow-horn pepper, aleva, bird pepper, red pepper"
pasilla pepper,,http://en.wikipedia.org/wiki/Pasilla,Capsicum annuum,"AKA chilaca pepper, chile negro"
chiltepin pepper,Capsicum annuum var. glabriusculum,http://en.wikipedia.org/wiki/Capsicum_annuum_var._glabriusculum,Capsicum annuum,"AKA wild chiltepin, chiltepe, chile tepin, turkey pepper, birds eye pepper, bird pepper"
Chungyang red pepper,,http://en.wikipedia.org/wiki/Chungyang_Red_Pepper,Capsicum annuum,
cubanelle pepper,,http://en.wikipedia.org/wiki/Cubanelle,Capsicum annuum,
chile de árbol pepper,,http://en.wikipedia.org/wiki/Chile_de_%C3%A1rbol,Capsicum annuum,"AKA bird's beak chile, rat's tail chile"
dundicut,,http://en.wikipedia.org/wiki/Dundicut,Capsicum annuum,AKA lal mirch
facing heaven pepper,Capsicum annuum var. conoides,http://en.wikipedia.org/wiki/Facing_heaven_pepper,Capsicum annuum,
Fresno pepper,,http://en.wikipedia.org/wiki/Fresno_pepper,Capsicum annuum,
guajillo pepper,,http://en.wikipedia.org/wiki/Guajillo_chili,Capsicum annuum,"AKA guajillo chili, guajillo chilli, chile guajillo"
Guntur Sannam chili,Capsicum Annuum var. Longhum,http://en.wikipedia.org/wiki/Guntur_Sannam,Capsicum annuum,
Hungarian wax pepper,,http://en.wikipedia.org/wiki/Hungarian_wax_pepper,Capsicum annuum,
Italian sweet pepper,,http://en.wikipedia.org/wiki/Italian_sweet_pepper,Capsicum annuum,
jalapeño pepper,,http://en.wikipedia.org/wiki/Jalape%C3%B1o,Capsicum annuum,
shishito pepper,,http://en.wikipedia.org/wiki/Shishito,Capsicum annuum,
medusa pepper,,http://en.wikipedia.org/wiki/Medusa_pepper,Capsicum annuum,
mulato pepper,,http://en.wikipedia.org/wiki/Mulato_pepper,Capsicum annuum,
peter pepper,Capsicum annuum var. annuum,http://en.wikipedia.org/wiki/Peter_pepper,Capsicum annuum,AKA chilli willy pepper
peperoncini pepper,,http://en.wikipedia.org/wiki/Peperoncini,Capsicum annuum,"AKA friggitello, peperone"
pequin pepper,"Capsicum annuum var. glabriusculum
",http://en.wikipedia.org/wiki/Pequin_pepper,Capsicum annuum,AKA piquin
pimento pepper,,http://en.wikipedia.org/wiki/Pimiento,Capsicum annuum,"AKA cherry pepper, pimiento pepper"
poblano pepper,,http://en.wikipedia.org/wiki/Poblano,Capsicum annuum,
Santa Fe Grande pepper,,http://en.wikipedia.org/wiki/Santa_Fe_Grande_pepper,Capsicum annuum,"AKA yellow hot chili pepper, guero chili pepper"
serrano pepper,,http://en.wikipedia.org/wiki/Serrano_pepper,Capsicum annuum,
bishop's crown pepper,Capsicum baccatum var. pendulum,http://en.wikipedia.org/wiki/Bishop%27s_Crown,Capsicum baccatum,AKA Christmas bell
lemon drop pepper,,http://en.wikipedia.org/wiki/Lemon_drop_%28pepper%29,Capsicum baccatum,"AKA ají limon, kellu uchu, hot lemon"
peppadew pepper,,http://en.wikipedia.org/wiki/Peppadew,Capsicum baccatum,
Brazilian starfish,,http://en.wikipedia.org/wiki/Capsicum_baccatum,Capsicum baccatum,
wild baccatum,,http://en.wikipedia.org/wiki/Capsicum_baccatum,Capsicum baccatum,
adjuma pepper,,http://en.wikipedia.org/wiki/Adjuma,Capsicum chinense,"AKA adjoema, aji umba, ojemma"
ají dulce pepper,,http://en.wikipedia.org/wiki/Aj%C3%AD_dulce,Capsicum chinense,"AKA ajicito, ajice, rubra, biquinho"
datil pepper,,http://en.wikipedia.org/wiki/Datil_pepper,Capsicum chinense,
fatalii pepper,,http://en.wikipedia.org/wiki/Fatalii,Capsicum chinense,
Madame Jeanette pepper,,http://en.wikipedia.org/wiki/Madame_Jeanette,Capsicum chinense,
habanero pepper,,http://en.wikipedia.org/wiki/Habanero,Capsicum chinense,AKA habañero
black habanero pepper,,http://en.wikipedia.org/wiki/Habanero,Capsicum chinense,
red savino pepper,,http://en.wikipedia.org/wiki/Red_Savina_pepper,Capsicum chinense,
bhut jolokia pepper,,http://en.wikipedia.org/wiki/Bhut_Jolokia,Capsicum chinense,"AKA ghost pepper, ghost chili pepper, red naga chilli, ghost chilli, naga jolokia"
Scotch bonnet pepper,,http://en.wikipedia.org/wiki/Scotch_bonnet_%28pepper%29,Capsicum chinense,"AKA boabs bonnet, Scotty bons, Bonney peppers, Caribbean red peppers, ball of fire"
cachucha pepper,,http://en.wikipedia.org/wiki/Scotch_bonnet_%28pepper%29,Capsicum chinense,
Trinidad scorpion butch T pepper,,http://en.wikipedia.org/wiki/Trinidad_Scorpion_Butch_T_pepper,Capsicum chinense,
Trinidad Moruga scorpion pepper,,http://en.wikipedia.org/wiki/Trinidad_Moruga_Scorpion,Capsicum chinense,
Hainan yellow lantern,,http://en.wikipedia.org/wiki/Hainan_Yellow_Lantern_Chili,Capsicum chinense,AKA yellow emperor chili
piri-piri pepper,,http://en.wikipedia.org/wiki/Piri_piri,Capsicum frutescens,"AKA African bird's eye pepper, peri peri, pili pili"
Tabasco pepper,,http://en.wikipedia.org/wiki/Tabasco_pepper,Capsicum frutescens,
malagueta pepper,,http://en.wikipedia.org/wiki/Malagueta_pepper,Capsicum frutescens,
siling labuyo pepper,,http://en.wikipedia.org/wiki/Siling_labuyo,Capsicum frutescens,"AKA chileng bundok, siling palay, pasitis, pasite, katumbal, kitikot, siling kolikot, silit-diablo, lada, rimorimo, paktin"
kambuzi,,http://en.wikipedia.org/wiki/Kambuzi,Capsicum frutescens,
1 Capsicum Capsicum http://en.wikipedia.org/wiki/Capsicum This is the top parent variety -- the entire family of all kinds of peppers
2 Capsicum annuum Capsicum annuum http://en.wikipedia.org/wiki/Capsicum_annuum Capsicum
3 Capsicum baccatum Capsicum baccatum http://en.wikipedia.org/wiki/Capsicum_baccatum Capsicum
4 Capsicum chinense Capsicum chinense http://en.wikipedia.org/wiki/Capsicum_chinense Capsicum
5 rocoto Capsicum pubescens http://en.wikipedia.org/wiki/Capsicum_pubescens Capsicum AKA locoto
6 Capsicum frutescens Capsicum frutescens http://en.wikipedia.org/wiki/Capsicum_frutescens Capsicum
7 Aleppo pepper http://en.wikipedia.org/wiki/Aleppo_pepper Capsicum annuum AKA pul biber, halaby pepper
8 Anaheim pepper http://en.wikipedia.org/wiki/Anaheim_pepper Capsicum annuum AKA New Mexico pepper, California chili, Magdalena chili
9 banana pepper http://en.wikipedia.org/wiki/Banana_pepper Capsicum annuum AKA yellow wax pepper, banana chili
10 bell pepper http://en.wikipedia.org/wiki/Bell_pepper Capsicum annuum AKA capsicum, sweet pepper, pepper, poivron, peperoni, piment
11 bird's eye chili http://en.wikipedia.org/wiki/Bird%27s_eye_chili Capsicum annuum AKA Thai chili pepper, bird's chili
12 cascabel chili http://en.wikipedia.org/wiki/Cascabel_chili Capsicum annuum AKA rattle chile, bola chile, chile bola
13 cayenne pepper http://en.wikipedia.org/wiki/Cayenne_pepper Capsicum annuum AKA Guinea spice, cow-horn pepper, aleva, bird pepper, red pepper
14 pasilla pepper http://en.wikipedia.org/wiki/Pasilla Capsicum annuum AKA chilaca pepper, chile negro
15 chiltepin pepper Capsicum annuum var. glabriusculum http://en.wikipedia.org/wiki/Capsicum_annuum_var._glabriusculum Capsicum annuum AKA wild chiltepin, chiltepe, chile tepin, turkey pepper, bird’s eye pepper, bird pepper
16 Chungyang red pepper http://en.wikipedia.org/wiki/Chungyang_Red_Pepper Capsicum annuum
17 cubanelle pepper http://en.wikipedia.org/wiki/Cubanelle Capsicum annuum
18 chile de árbol pepper http://en.wikipedia.org/wiki/Chile_de_%C3%A1rbol Capsicum annuum AKA bird's beak chile, rat's tail chile
19 dundicut http://en.wikipedia.org/wiki/Dundicut Capsicum annuum AKA lal mirch
20 facing heaven pepper Capsicum annuum var. conoides http://en.wikipedia.org/wiki/Facing_heaven_pepper Capsicum annuum
21 Fresno pepper http://en.wikipedia.org/wiki/Fresno_pepper Capsicum annuum
22 guajillo pepper http://en.wikipedia.org/wiki/Guajillo_chili Capsicum annuum AKA guajillo chili, guajillo chilli, chile guajillo
23 Guntur Sannam chili Capsicum Annuum var. Longhum http://en.wikipedia.org/wiki/Guntur_Sannam Capsicum annuum
24 Hungarian wax pepper http://en.wikipedia.org/wiki/Hungarian_wax_pepper Capsicum annuum
25 Italian sweet pepper http://en.wikipedia.org/wiki/Italian_sweet_pepper Capsicum annuum
26 jalapeño pepper http://en.wikipedia.org/wiki/Jalape%C3%B1o Capsicum annuum
27 shishito pepper http://en.wikipedia.org/wiki/Shishito Capsicum annuum
28 medusa pepper http://en.wikipedia.org/wiki/Medusa_pepper Capsicum annuum
29 mulato pepper http://en.wikipedia.org/wiki/Mulato_pepper Capsicum annuum
30 peter pepper Capsicum annuum var. annuum http://en.wikipedia.org/wiki/Peter_pepper Capsicum annuum AKA chilli willy pepper
31 peperoncini pepper http://en.wikipedia.org/wiki/Peperoncini Capsicum annuum AKA friggitello, peperone
32 pequin pepper Capsicum annuum var. glabriusculum http://en.wikipedia.org/wiki/Pequin_pepper Capsicum annuum AKA piquin
33 pimento pepper http://en.wikipedia.org/wiki/Pimiento Capsicum annuum AKA cherry pepper, pimiento pepper
34 poblano pepper http://en.wikipedia.org/wiki/Poblano Capsicum annuum
35 Santa Fe Grande pepper http://en.wikipedia.org/wiki/Santa_Fe_Grande_pepper Capsicum annuum AKA yellow hot chili pepper, guero chili pepper
36 serrano pepper http://en.wikipedia.org/wiki/Serrano_pepper Capsicum annuum
37 bishop's crown pepper Capsicum baccatum var. pendulum http://en.wikipedia.org/wiki/Bishop%27s_Crown Capsicum baccatum AKA Christmas bell
38 lemon drop pepper http://en.wikipedia.org/wiki/Lemon_drop_%28pepper%29 Capsicum baccatum AKA ají limon, kellu uchu, hot lemon
39 peppadew pepper http://en.wikipedia.org/wiki/Peppadew Capsicum baccatum
40 Brazilian starfish http://en.wikipedia.org/wiki/Capsicum_baccatum Capsicum baccatum
41 wild baccatum http://en.wikipedia.org/wiki/Capsicum_baccatum Capsicum baccatum
42 adjuma pepper http://en.wikipedia.org/wiki/Adjuma Capsicum chinense AKA adjoema, aji umba, ojemma
43 ají dulce pepper http://en.wikipedia.org/wiki/Aj%C3%AD_dulce Capsicum chinense AKA ajicito, ajice, rubra, biquinho
44 datil pepper http://en.wikipedia.org/wiki/Datil_pepper Capsicum chinense
45 fatalii pepper http://en.wikipedia.org/wiki/Fatalii Capsicum chinense
46 Madame Jeanette pepper http://en.wikipedia.org/wiki/Madame_Jeanette Capsicum chinense
47 habanero pepper http://en.wikipedia.org/wiki/Habanero Capsicum chinense AKA habañero
48 black habanero pepper http://en.wikipedia.org/wiki/Habanero Capsicum chinense
49 red savino pepper http://en.wikipedia.org/wiki/Red_Savina_pepper Capsicum chinense
50 bhut jolokia pepper http://en.wikipedia.org/wiki/Bhut_Jolokia Capsicum chinense AKA ghost pepper, ghost chili pepper, red naga chilli, ghost chilli, naga jolokia
51 Scotch bonnet pepper http://en.wikipedia.org/wiki/Scotch_bonnet_%28pepper%29 Capsicum chinense AKA boabs bonnet, Scotty bons, Bonney peppers, Caribbean red peppers, ball of fire
52 cachucha pepper http://en.wikipedia.org/wiki/Scotch_bonnet_%28pepper%29 Capsicum chinense
53 Trinidad scorpion butch T pepper http://en.wikipedia.org/wiki/Trinidad_Scorpion_Butch_T_pepper Capsicum chinense
54 Trinidad Moruga scorpion pepper http://en.wikipedia.org/wiki/Trinidad_Moruga_Scorpion Capsicum chinense
55 Hainan yellow lantern http://en.wikipedia.org/wiki/Hainan_Yellow_Lantern_Chili Capsicum chinense AKA yellow emperor chili
56 piri-piri pepper http://en.wikipedia.org/wiki/Piri_piri Capsicum frutescens AKA African bird's eye pepper, peri peri, pili pili
57 Tabasco pepper http://en.wikipedia.org/wiki/Tabasco_pepper Capsicum frutescens
58 malagueta pepper http://en.wikipedia.org/wiki/Malagueta_pepper Capsicum frutescens
59 siling labuyo pepper http://en.wikipedia.org/wiki/Siling_labuyo Capsicum frutescens AKA chileng bundok, siling palay, pasitis, pasite, katumbal, kitikot, siling kolikot, silit-diablo, lada, rimorimo, paktin
60 kambuzi http://en.wikipedia.org/wiki/Kambuzi Capsicum frutescens

22
lib/geocodable.rb Normal file
View File

@@ -0,0 +1,22 @@
module Geocodable
def self.included(base)
base.extend(self)
end
private
def geocode
unless self.location.blank?
self.latitude, self.longitude =
Geocoder.coordinates(location, params: {limit: 1})
end
end
def empty_unwanted_geocodes
if self.location.blank?
self.latitude = nil
self.longitude = nil
end
end
end

View File

@@ -10,6 +10,32 @@ namespace :growstuff do
member.roles << admin
end
desc "Upload crops from a CSV file"
# usage: rake growstuff:import_crops file=filename.csv
task :import_crops => :environment do
require 'csv'
@file = ENV['file'] or raise "Usage: rake growstuff:import_crops file=file.csv"
puts "Loading crops from #{@file}..."
CSV.foreach(@file) do |row|
Crop.create_from_csv(row)
end
puts "Finished loading crops"
end
desc "Depopulate Null Island"
# this fixes up anyone who has erroneously wound up with a 0,0 lat/long
task :depopulate_null_island => :environment do
Member.find_each do |m|
if m.location and (m.latitude == nil and m.longitude == nil)
m.geocode
m.save
end
end
end
desc "One-off tasks needed at various times and kept for posterity"
namespace :oneoff do
@@ -167,6 +193,21 @@ namespace :growstuff do
end
end
desc "October 2013: set garden locations to member locations"
task :initialize_garden_locations => :environment do
Member.located.find_each do |m|
m.gardens.each do |g|
if g.location.blank?
g.location = m.location
g.latitude = m.latitude
g.longitude = m.longitude
g.save
end
end
end
end
end
end

View File

@@ -10,8 +10,9 @@
# echo "YYYY-MM-DD - do something or other"
# rake growstuff:oneoff:something
echo "2013-08-26 - set planting owner"
rake growstuff:oneoff:set_planting_owner
echo "2013-10-24 - fix zeroed geolocations"
rake growstuff:depopulate_null_island
echo "2013-10-24 - initialize garden locations"
rake growstuff:oneoff:initialize_garden_locations
echo "2013-08-26 - initialize member planting count"
rake growstuff:oneoff:initialize_member_planting_count

View File

@@ -2,4 +2,20 @@ require 'spec_helper'
describe Admin::OrdersController do
login_member(:admin_member)
describe "GET search" do
it "assigns @orders" do
order = FactoryGirl.create(:order)
get :search, {:search_by => 'order_id', :search_text => order.id}
assigns(:orders).should eq([order])
end
it "sets an error message if nothing found" do
order = FactoryGirl.create(:order)
get :search, {:search_by => 'order_id', :search_text => 'foo'}
flash[:alert].should match /Couldn't find order with/
end
end
end

View File

@@ -6,7 +6,7 @@ describe CropsController do
def valid_attributes
{
:system_name => "Tomato",
:name => "Tomato",
:en_wikipedia_url => 'http://en.wikipedia.org/wiki/Tomato'
}
end

View File

@@ -0,0 +1,141 @@
require 'spec_helper'
describe HarvestsController do
login_member
def valid_attributes
{
:owner_id => subject.current_member.id,
:crop_id => FactoryGirl.create(:crop).id
}
end
describe "GET index" do
it "assigns all harvests as @harvests" do
harvest = Harvest.create! valid_attributes
get :index, {}
assigns(:harvests).should eq([harvest])
end
end
describe "GET show" do
it "assigns the requested harvest as @harvest" do
harvest = Harvest.create! valid_attributes
get :show, {:id => harvest.to_param}
assigns(:harvest).should eq(harvest)
end
end
describe "GET new" do
it "assigns a new harvest as @harvest" do
get :new, {}
assigns(:harvest).should be_a_new(Harvest)
end
end
describe "GET edit" do
it "assigns the requested harvest as @harvest" do
harvest = Harvest.create! valid_attributes
get :edit, {:id => harvest.to_param}
assigns(:harvest).should eq(harvest)
end
end
describe "POST create" do
describe "with valid params" do
it "creates a new Harvest" do
expect {
post :create, {:harvest => valid_attributes}
}.to change(Harvest, :count).by(1)
end
it "assigns a newly created harvest as @harvest" do
post :create, {:harvest => valid_attributes}
assigns(:harvest).should be_a(Harvest)
assigns(:harvest).should be_persisted
end
it "redirects to the created harvest" do
post :create, {:harvest => valid_attributes}
response.should redirect_to(Harvest.last)
end
end
describe "with invalid params" do
it "assigns a newly created but unsaved harvest as @harvest" do
# Trigger the behavior that occurs when invalid params are submitted
Harvest.any_instance.stub(:save).and_return(false)
post :create, {:harvest => { "crop_id" => "invalid value" }}
assigns(:harvest).should be_a_new(Harvest)
end
it "re-renders the 'new' template" do
# Trigger the behavior that occurs when invalid params are submitted
Harvest.any_instance.stub(:save).and_return(false)
post :create, {:harvest => { "crop_id" => "invalid value" }}
response.should render_template("new")
end
end
end
describe "PUT update" do
describe "with valid params" do
it "updates the requested harvest" do
harvest = Harvest.create! valid_attributes
# Assuming there are no other harvests in the database, this
# specifies that the Harvest created on the previous line
# receives the :update_attributes message with whatever params are
# submitted in the request.
Harvest.any_instance.should_receive(:update_attributes).with({ "crop_id" => "1" })
put :update, {:id => harvest.to_param, :harvest => { "crop_id" => "1" }}
end
it "assigns the requested harvest as @harvest" do
harvest = Harvest.create! valid_attributes
put :update, {:id => harvest.to_param, :harvest => valid_attributes}
assigns(:harvest).should eq(harvest)
end
it "redirects to the harvest" do
harvest = Harvest.create! valid_attributes
put :update, {:id => harvest.to_param, :harvest => valid_attributes}
response.should redirect_to(harvest)
end
end
describe "with invalid params" do
it "assigns the harvest as @harvest" do
harvest = Harvest.create! valid_attributes
# Trigger the behavior that occurs when invalid params are submitted
Harvest.any_instance.stub(:save).and_return(false)
put :update, {:id => harvest.to_param, :harvest => { "crop_id" => "invalid value" }}
assigns(:harvest).should eq(harvest)
end
it "re-renders the 'edit' template" do
harvest = Harvest.create! valid_attributes
# Trigger the behavior that occurs when invalid params are submitted
Harvest.any_instance.stub(:save).and_return(false)
put :update, {:id => harvest.to_param, :harvest => { "crop_id" => "invalid value" }}
response.should render_template("edit")
end
end
end
describe "DELETE destroy" do
it "destroys the requested harvest" do
harvest = Harvest.create! valid_attributes
expect {
delete :destroy, {:id => harvest.to_param}
}.to change(Harvest, :count).by(-1)
end
it "redirects to the harvests list" do
harvest = Harvest.create! valid_attributes
delete :destroy, {:id => harvest.to_param}
response.should redirect_to(harvests_url)
end
end
end

View File

@@ -13,6 +13,15 @@ describe OrdersController do
end
describe "GET checkout" do
it 'sets the referral_code' do
member = FactoryGirl.create(:member)
sign_in member
order = Order.create!(:member_id => member.id)
get :checkout, {:id => order.to_param, :referral_code => 'FOOBAR'}
order.reload
order.referral_code.should eq 'FOOBAR'
end
it "redirects to Paypal" do
member = FactoryGirl.create(:member)
sign_in member

View File

@@ -1,54 +1,54 @@
FactoryGirl.define do
factory :crop do
system_name "Magic bean"
name "Magic bean"
en_wikipedia_url "http://en.wikipedia.org/wiki/Magic_bean"
creator
factory :tomato do
system_name "Tomato"
name "Tomato"
en_wikipedia_url "http://en.wikipedia.org/wiki/Tomato"
end
factory :maize do
system_name "Maize"
name "Maize"
en_wikipedia_url "http://en.wikipedia.org/wiki/Maize"
end
factory :chard do
system_name "Chard"
name "Chard"
end
factory :walnut do
system_name "Walnut"
name "Walnut"
end
factory :apple do
system_name "Apple"
name "Apple"
end
factory :pear do
system_name "Pear"
name "Pear"
end
# for testing varieties
factory :roma do
system_name "Roma tomato"
name "Roma tomato"
end
factory :popcorn do
system_name "popcorn"
name "popcorn"
end
# This should have a name that is alphabetically earlier than :uppercase
# crop to ensure that the ordering tests work.
factory :lowercasecrop do
system_name "ffrench bean"
name "ffrench bean"
end
factory :uppercasecrop do
system_name "Swiss chard"
name "Swiss chard"
end
end

View File

@@ -3,6 +3,14 @@ FactoryGirl.define do
name 'Springfield Community Garden'
description "This is a **totally** cool garden"
owner
active true
area 23
area_unit "acre"
location "Greenwich, UK"
factory :inactive_garden do
active false
end
# the following are used for testing alphabetical ordering
factory :garden_a do

View File

@@ -0,0 +1,14 @@
# Read about factories at https://github.com/thoughtbot/factory_girl
FactoryGirl.define do
factory :harvest do
crop
owner
harvested_at "2013-09-17"
quantity "3"
unit "individual"
weight_quantity 6
weight_unit "kg"
description "A lovely harvest"
end
end

View File

@@ -6,5 +6,9 @@ FactoryGirl.define do
factory :completed_order do
completed_at '2013-05-08 01:01:01'
end
factory :referred_order do
referral_code 'CAMPAIGN1'
end
end
end

View File

@@ -0,0 +1,79 @@
require 'spec_helper'
describe HarvestsHelper do
describe "display_quantity" do
it "blank" do
harvest = FactoryGirl.create(:harvest,
:quantity => nil,
:weight_quantity => nil
)
result = helper.display_quantity(harvest)
result.should eq 'not specified'
end
it '3 individual' do
harvest = FactoryGirl.create(:harvest,
:quantity => 3,
:unit => 'individual',
:weight_quantity => nil
)
result = helper.display_quantity(harvest)
result.should eq '3'
end
it '1 bunch' do
harvest = FactoryGirl.create(:harvest,
:quantity => 1,
:unit => 'bunch',
:weight_quantity => nil
)
result = helper.display_quantity(harvest)
result.should eq '1 bunch'
end
it '3 bunches' do
harvest = FactoryGirl.create(:harvest,
:quantity => 3,
:unit => 'bunch',
:weight_quantity => nil
)
result = helper.display_quantity(harvest)
result.should eq '3 bunches'
end
it '3 kg' do
harvest = FactoryGirl.create(:harvest,
:quantity => nil,
:unit => nil,
:weight_quantity => 3,
:weight_unit => 'kg'
)
result = helper.display_quantity(harvest)
result.should eq '3 kg'
end
it '3 individual weighing 3 kg' do
harvest = FactoryGirl.create(:harvest,
:quantity => 3,
:unit => 'individual',
:weight_quantity => 3,
:weight_unit => 'kg'
)
result = helper.display_quantity(harvest)
result.should eq '3, weighing 3 kg'
end
it '3 bunches weighing 3 kg' do
harvest = FactoryGirl.create(:harvest,
:quantity => 3,
:unit => 'bunch',
:weight_quantity => 3,
:weight_unit => 'kg'
)
result = helper.display_quantity(harvest)
result.should eq '3 bunches, weighing 3 kg'
end
end
end

View File

@@ -13,7 +13,7 @@ describe Crop do
it 'should be fetchable from the database' do
@crop.save
@crop2 = Crop.find_by_system_name('Tomato')
@crop2 = Crop.find_by_name('Tomato')
@crop2.en_wikipedia_url.should == "http://en.wikipedia.org/wiki/Tomato"
@crop2.slug.should == "tomato"
end
@@ -32,7 +32,7 @@ describe Crop do
context 'invalid data' do
it 'should not save a crop without a system name' do
@crop = FactoryGirl.build(:crop, :system_name => nil)
@crop = FactoryGirl.build(:crop, :name => nil)
expect { @crop.save }.to raise_error ActiveRecord::StatementInvalid
end
end
@@ -235,4 +235,12 @@ describe Crop do
end
context "harvests" do
it "has harvests" do
crop = FactoryGirl.create(:crop)
harvest = FactoryGirl.create(:harvest, :crop => crop)
crop.harvests.should eq [harvest]
end
end
end

View File

@@ -23,7 +23,7 @@ describe Garden do
@garden = FactoryGirl.build(:garden, :name => "")
@garden.should_not be_valid
end
it "doesn't allow a name with only spaces" do
@garden = FactoryGirl.build(:garden, :name => " ")
@garden.should_not be_valid
@@ -96,4 +96,73 @@ describe Garden do
Planting.count.should == all - 2
end
context 'area' do
it 'allows numeric area' do
@garden = FactoryGirl.build(:garden, :area => 33)
@garden.should be_valid
end
it 'allows decimal quantities' do
@garden = FactoryGirl.build(:garden, :area => 3.3)
@garden.should be_valid
end
it 'allows blank quantities' do
@garden = FactoryGirl.build(:garden, :area => '')
@garden.should be_valid
end
it 'allows nil quantities' do
@garden = FactoryGirl.build(:garden, :area => nil)
@garden.should be_valid
end
it 'cleans up zero quantities' do
@garden = FactoryGirl.build(:garden, :area => 0)
@garden.area.should == 0
end
it "doesn't allow non-numeric quantities" do
@garden = FactoryGirl.build(:garden, :area => "99a")
@garden.should_not be_valid
end
end
context 'units' do
Garden::AREA_UNITS_VALUES.values.push(nil, '').each do |s|
it "#{s} should be a valid unit" do
@garden = FactoryGirl.build(:garden, :area_unit => s)
@garden.should be_valid
end
end
it 'should refuse invalid unit values' do
@garden = FactoryGirl.build(:garden, :area_unit => 'not valid')
@garden.should_not be_valid
@garden.errors[:area_unit].should include("not valid is not a valid area unit")
end
it 'sets area unit to blank if area is blank' do
@garden = FactoryGirl.build(:garden, :area => '', :area_unit => 'acre')
@garden.should be_valid
@garden.area_unit.should eq nil
end
end
context 'active scopes' do
before(:each) do
@active = FactoryGirl.create(:garden)
@inactive = FactoryGirl.create(:inactive_garden)
end
it 'includes active garden in active scope' do
Garden.active.should include @active
Garden.active.should_not include @inactive
end
it 'includes inactive garden in inactive scope' do
Garden.inactive.should include @inactive
Garden.inactive.should_not include @active
end
end
end

128
spec/models/harvest_spec.rb Normal file
View File

@@ -0,0 +1,128 @@
require 'spec_helper'
describe Harvest do
it "has an owner" do
harvest = FactoryGirl.create(:harvest)
harvest.owner.should be_an_instance_of Member
end
it "has a crop" do
harvest = FactoryGirl.create(:harvest)
harvest.crop.should be_an_instance_of Crop
end
context 'quantity' do
it 'allows numeric quantities' do
@harvest = FactoryGirl.build(:harvest, :quantity => 33)
@harvest.should be_valid
end
it 'allows decimal quantities' do
@harvest = FactoryGirl.build(:harvest, :quantity => 3.3)
@harvest.should be_valid
end
it 'allows blank quantities' do
@harvest = FactoryGirl.build(:harvest, :quantity => '')
@harvest.should be_valid
end
it 'allows nil quantities' do
@harvest = FactoryGirl.build(:harvest, :quantity => nil)
@harvest.should be_valid
end
it 'cleans up zero quantities' do
@harvest = FactoryGirl.build(:harvest, :quantity => 0)
@harvest.quantity.should == 0
end
it "doesn't allow non-numeric quantities" do
@harvest = FactoryGirl.build(:harvest, :quantity => "99a")
@harvest.should_not be_valid
end
end
context 'units' do
Harvest::UNITS_VALUES.values.push(nil, '').each do |s|
it "#{s} should be a valid unit" do
@harvest = FactoryGirl.build(:harvest, :unit => s)
@harvest.should be_valid
end
end
it 'should refuse invalid unit values' do
@harvest = FactoryGirl.build(:harvest, :unit => 'not valid')
@harvest.should_not be_valid
@harvest.errors[:unit].should include("not valid is not a valid unit")
end
it 'sets unit to blank if quantity is blank' do
@harvest = FactoryGirl.build(:harvest, :quantity => '', :unit => 'individual')
@harvest.should be_valid
@harvest.unit.should eq nil
end
end
context 'weight quantity' do
it 'allows numeric weight quantities' do
@harvest = FactoryGirl.build(:harvest, :weight_quantity => 33)
@harvest.should be_valid
end
it 'allows decimal weight quantities' do
@harvest = FactoryGirl.build(:harvest, :weight_quantity => 3.3)
@harvest.should be_valid
end
it 'allows blank weight quantities' do
@harvest = FactoryGirl.build(:harvest, :weight_quantity => '')
@harvest.should be_valid
end
it 'allows nil weight quantities' do
@harvest = FactoryGirl.build(:harvest, :weight_quantity => nil)
@harvest.should be_valid
end
it 'cleans up zero quantities' do
@harvest = FactoryGirl.build(:harvest, :weight_quantity => 0)
@harvest.weight_quantity.should == 0
end
it "doesn't allow non-numeric weight quantities" do
@harvest = FactoryGirl.build(:harvest, :weight_quantity => "99a")
@harvest.should_not be_valid
end
end
context 'weight units' do
it 'all valid units should work' do
['kg', 'lb', nil, ''].each do |s|
@harvest = FactoryGirl.build(:harvest, :weight_unit => s)
@harvest.should be_valid
end
end
it 'should refuse invalid weight unit values' do
@harvest = FactoryGirl.build(:harvest, :weight_unit => 'not valid')
@harvest.should_not be_valid
@harvest.errors[:weight_unit].should include("not valid is not a valid unit")
end
it 'sets weight_unit to blank if quantity is blank' do
@harvest = FactoryGirl.build(:harvest, :weight_quantity => '', :weight_unit => 'kg')
@harvest.should be_valid
@harvest.weight_unit.should eq nil
end
end
context 'ordering' do
it 'lists most recent harvests first' do
@h1 = FactoryGirl.create(:harvest, :created_at => 1.day.ago)
@h2 = FactoryGirl.create(:harvest, :created_at => 1.hour.ago)
Harvest.all.should eq [@h2, @h1]
end
end
end

View File

@@ -373,4 +373,12 @@ describe 'member' do
end
end
context 'harvests' do
it 'has harvests' do
member = FactoryGirl.create(:member)
harvest = FactoryGirl.create(:harvest, :owner => member)
member.harvests.should eq [harvest]
end
end
end

View File

@@ -84,4 +84,49 @@ describe Order do
end
context "referral codes" do
it "has a referral code" do
referred_order = FactoryGirl.create(:referred_order)
referred_order.referral_code.should_not be nil
end
it "validates referral codes" do
referred_order = FactoryGirl.build(:order, :referral_code => 'CAMP_AIGN1?')
referred_order.should_not be_valid
end
it "cleans up messy referral codes" do
referred_order = FactoryGirl.create(:order, :referral_code => 'CaMpAiGn 1 ')
referred_order.referral_code.should eq 'CAMPAIGN1'
end
end
context 'search' do
it 'finds orders by member' do
order = FactoryGirl.create(:order)
Order.search(:by => 'member', :for => order.member.login_name).should eq [order]
end
it 'finds orders by order_id' do
order = FactoryGirl.create(:order)
Order.search(:by => 'order_id', :for => order.id).should eq [order]
end
it 'finds orders by paypal_token' do
order = FactoryGirl.create(:order, :paypal_express_token => 'foo')
Order.search(:by => 'paypal_token', :for => 'foo').should eq [order]
end
it 'finds orders by paypal_payer_id' do
order = FactoryGirl.create(:order, :paypal_express_payer_id => 'bar')
Order.search(:by => 'paypal_payer_id', :for => 'bar').should eq [order]
end
it 'finds orders by referral_code' do
order = FactoryGirl.create(:order, :referral_code => 'baz')
Order.search(:by => 'referral_code', :for => 'baz').should eq [order]
end
end
end

View File

@@ -41,7 +41,7 @@ describe Planting do
context 'delegation' do
it 'system name' do
@planting.crop_system_name.should eq @planting.crop.system_name
@planting.crop_name.should eq @planting.crop.name
end
it 'wikipedia url' do
@planting.crop_en_wikipedia_url.should eq @planting.crop.en_wikipedia_url

View File

@@ -14,7 +14,7 @@ describe ScientificName do
it 'should be fetchable from the database' do
@sn.save
@sn2 = ScientificName.find_by_scientific_name('Zea mays')
@sn2.crop.system_name.should == "Maize"
@sn2.crop.name.should == "Maize"
end
it 'has a creator' do

View File

@@ -0,0 +1,11 @@
require 'spec_helper'
describe "Harvests" do
describe "GET /harvests" do
it "works! (now write some real specs)" do
# Run the generator again with the --webrat flag if you want to use webrat methods/matchers
get harvests_path
response.status.should be(200)
end
end
end

View File

@@ -0,0 +1,35 @@
require "spec_helper"
describe HarvestsController do
describe "routing" do
it "routes to #index" do
get("/harvests").should route_to("harvests#index")
end
it "routes to #new" do
get("/harvests/new").should route_to("harvests#new")
end
it "routes to #show" do
get("/harvests/1").should route_to("harvests#show", :id => "1")
end
it "routes to #edit" do
get("/harvests/1/edit").should route_to("harvests#edit", :id => "1")
end
it "routes to #create" do
post("/harvests").should route_to("harvests#create")
end
it "routes to #update" do
put("/harvests/1").should route_to("harvests#update", :id => "1")
end
it "routes to #destroy" do
delete("/harvests/1").should route_to("harvests#destroy", :id => "1")
end
end
end

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