Compare commits

..

22 Commits

Author SHA1 Message Date
Daniel O'Connor
6ee86b6b38 Merge branch 'dev' into refactor-hardcoded-emails 2026-04-27 00:36:06 +09:30
Daniel O'Connor
573daa8c8a Swap to modern expect style (#4571) 2026-04-26 22:58:04 +09:30
Daniel O'Connor
5174b1236e Merge pull request #4567 from Growstuff/memory-optimisation-3
Members - Nearest To - Memory improvements
2026-04-26 22:57:01 +09:30
Daniel O'Connor
5a349f8f1b Swap to modern expect style 2026-04-26 13:21:15 +00:00
Daniel O'Connor
0d850804cf Merge pull request #4570 from Growstuff/rubocop-tweaks
Rubocop fixes
2026-04-26 22:47:46 +09:30
Daniel O'Connor
161a934811 Merge pull request #4569 from Growstuff/plant_part_spec
Rubocop: Fix no expectation errors
2026-04-26 22:44:49 +09:30
Daniel O'Connor
8cfef5ce1a Rubocop fixes 2026-04-26 13:09:00 +00:00
Daniel O'Connor
6dacb0af74 Swap to modern expect style 2026-04-26 13:03:46 +00:00
Daniel O'Connor
7e2d36f99a Swap to modern expect style 2026-04-26 12:55:58 +00:00
Daniel O'Connor
3406d9e7bc Merge pull request #4568 from Growstuff/memory-usage-4
Posts - memory usage
2026-04-26 19:05:56 +09:30
Daniel O'Connor
7a91746f73 Update .dockerignore to remove .ruby-version
Remove .ruby-version from .dockerignore
2026-04-26 19:05:41 +09:30
Daniel O'Connor
209973e72b Memory usage 2026-04-26 09:26:52 +00:00
Daniel O'Connor
4848302eab Merge pull request #4565 from Growstuff/memory-usage-1
Admin - Members - optimise memory usage
2026-04-26 18:45:12 +09:30
Daniel O'Connor
920a28a144 Merge pull request #4566 from Growstuff/memory-usage-2
GBIF - optimise memory usage
2026-04-26 18:44:58 +09:30
Daniel O'Connor
fff7a14635 GBIF - optimise memory usage 2026-04-26 09:03:45 +00:00
Daniel O'Connor
0131c9b531 Admin - Members - optimise memory usage 2026-04-26 09:01:18 +00:00
Daniel O'Connor
1b091b2f6f Merge pull request #4453 from Growstuff/add-mark-as-failed-to-crop-view-13853484652230549508
Add "mark as failed" action to crop view
2026-04-26 14:44:09 +09:30
Daniel O'Connor
dc11a1674d Merge branch 'dev' into refactor-hardcoded-emails 2026-04-24 00:03:30 +09:30
google-labs-jules[bot]
8bafba7f9d Ensure "mark as failed" option is available when viewing a crop
This change adds the "mark as failed" action to the crop view in two places:
1. In the "Crop Actions" button group, a new "Mark as failed" button is added if the current member has active plantings of that crop. Clicking it opens a modal to select which planting failed.
2. In the "See who's planted" list, an "Actions" dropdown is added to any plantings owned by the current member, which includes the "Mark as failed" option.

A new partial `app/views/plantings/_failed_modal.html.haml` was created to handle the planting selection modal.
`app/views/crops/_actions.html.haml` and `app/views/crops/_plantings.html.haml` were updated to include these new actions.

Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com>
2026-02-22 00:08:58 +00:00
Daniel O'Connor
4085014e06 Merge branch 'dev' into refactor-hardcoded-emails 2025-10-09 22:54:33 +10:30
Daniel O'Connor
18986ee133 Merge branch 'dev' into refactor-hardcoded-emails 2025-09-01 15:40:20 +09:30
google-labs-jules[bot]
f5a4ba60fe Refactor hardcoded emails to a central configuration 2025-08-31 05:38:33 +00:00
47 changed files with 178 additions and 135 deletions

View File

@@ -7,7 +7,6 @@ tmp/*
node_modules node_modules
public/assets public/assets
.env .env
.ruby-version
.ruby-gemset .ruby-gemset
.editorconfig .editorconfig
.esignore .esignore

View File

@@ -8,9 +8,9 @@ module Admin
responders :flash responders :flash
def index def index
@members = Member.all @members = Member.order(:login_name)
@members = @members.where("login_name ILIKE ?", "%#{search_term}%") unless search_term.nil? @members = @members.where("login_name ILIKE ?", "%#{search_term}%") if search_term.present?
@members = @members.order(:login_name).paginate(page: params[:page]) @members = @members.paginate(page: params[:page])
end end
def edit def edit

View File

@@ -12,7 +12,7 @@ class BlocksController < ApplicationController
else else
flash[:error] = "Already blocking or error while blocking." flash[:error] = "Already blocking or error while blocking."
end end
redirect_back fallback_location: root_path redirect_back_or_to(root_path)
end end
def destroy def destroy

View File

@@ -39,7 +39,7 @@ class MessagesController < ApplicationController
recipient = Member.find(params[:recipient_id]) recipient = Member.find(params[:recipient_id])
if recipient.already_blocking?(current_member) if recipient.already_blocking?(current_member)
flash[:error] = "You cannot send a message to a member who has blocked you." flash[:error] = "You cannot send a message to a member who has blocked you."
redirect_back fallback_location: root_path redirect_back_or_to(root_path)
return return
end end
body = params[:body] body = params[:body]

View File

@@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
class ApplicationMailer < ActionMailer::Base class ApplicationMailer < ActionMailer::Base
default from: 'from@example.com' default from: "Growstuff <#{Rails.configuration.x.email[:from]}>"
layout 'mailer' layout 'mailer'
end end

View File

@@ -2,7 +2,7 @@
class NotifierMailer < ApplicationMailer class NotifierMailer < ApplicationMailer
# include NotificationsHelper # include NotificationsHelper
default from: "Growstuff <#{ENV.fetch('GROWSTUFF_EMAIL', nil)}>" default from: "Growstuff <#{Rails.configuration.x.email[:from]}>"
def verifier def verifier
unless ENV['RAILS_SECRET_TOKEN'] unless ENV['RAILS_SECRET_TOKEN']

View File

@@ -31,8 +31,9 @@ class Comment < ApplicationRecord
def author_is_not_blocked def author_is_not_blocked
return unless author return unless author
if commentable.author.already_blocking?(author)
errors.add(:base, "You cannot comment on a post of a member who has blocked you.") return unless commentable.author.already_blocking?(author)
end
errors.add(:base, "You cannot comment on a post of a member who has blocked you.")
end end
end end

View File

@@ -20,8 +20,9 @@ class Follow < ApplicationRecord
def follower_is_not_blocked def follower_is_not_blocked
return unless follower return unless follower
if followed.already_blocking?(follower)
errors.add(:base, "You cannot follow a member who has blocked you.") return unless followed.already_blocking?(follower)
end
errors.add(:base, "You cannot follow a member who has blocked you.")
end end
end end

View File

@@ -19,9 +19,10 @@ class Like < ApplicationRecord
def member_is_not_blocked def member_is_not_blocked
return unless member return unless member
author = likeable_author author = likeable_author
if author && author.already_blocking?(member) return unless author&.already_blocking?(member)
errors.add(:base, "You cannot like content of a member who has blocked you.")
end errors.add(:base, "You cannot like content of a member who has blocked you.")
end end
end end

View File

@@ -173,12 +173,12 @@ class Member < ApplicationRecord
end end
def self.nearest_to(place) def self.nearest_to(place)
nearby_members = [] return [] if place.blank?
if place
latitude, longitude = Geocoder.coordinates(place, params: { limit: 1 }) latitude, longitude = Geocoder.coordinates(place, params: { limit: 1 })
nearby_members = Member.located.sort_by { |x| x.distance_from([latitude, longitude]) } if latitude && longitude return [] unless latitude && longitude
end
nearby_members Member.located.near([latitude, longitude], 1000)
end end
def already_following?(member) def already_following?(member)

View File

@@ -49,9 +49,10 @@ class Post < ApplicationRecord
# return posts sorted by recent activity # return posts sorted by recent activity
def self.recently_active def self.recently_active
Post.order(created_at: :desc).sort do |a, b| left_joins(:comments)
b.recent_activity <=> a.recent_activity .select('posts.*, COALESCE(MAX(comments.created_at), posts.created_at) AS last_activity_at')
end .group('posts.id')
.order(Arel.sql('last_activity_at DESC'))
end end
def owner_id def owner_id

View File

@@ -85,7 +85,7 @@ class GbifService
end end
def import! def import!
Crop.order(updated_at: :desc).each do |crop| Crop.order(updated_at: :desc).find_each do |crop|
Rails.logger.debug { "#{crop.id}, #{crop.name}" } Rails.logger.debug { "#{crop.id}, #{crop.name}" }
update_crop(crop) if crop.valid? update_crop(crop) if crop.valid?
rescue ActiveRecord::RecordInvalid rescue ActiveRecord::RecordInvalid

View File

@@ -1,6 +1,9 @@
- if crop.approved? && signed_in? - if crop.approved? && signed_in?
- active_plantings = current_member.plantings.where(crop: crop).active
.btn-group.crop-actions{"aria-label" => "Crop Actions", role: "group"} .btn-group.crop-actions{"aria-label" => "Crop Actions", role: "group"}
= render 'plantings/modal', planting: Planting.new(crop: crop, owner: current_member) = render 'plantings/modal', planting: Planting.new(crop: crop, owner: current_member)
= render 'harvests/modal', harvest: Harvest.new(crop: @crop, owner: current_member) = render 'harvests/modal', harvest: Harvest.new(crop: @crop, owner: current_member)
= render 'seeds/modal', seed: Seed.new(crop: @crop, owner: current_member) = render 'seeds/modal', seed: Seed.new(crop: @crop, owner: current_member)
- if active_plantings.any?
= render 'plantings/failed_modal', crop: crop, active_plantings: active_plantings

View File

@@ -8,6 +8,8 @@
= link_to planting_path(planting), class: 'card-link' do = link_to planting_path(planting), class: 'card-link' do
= planting_icon = planting_icon
= planting = planting
- if can?(:edit, planting)
.float-right= render 'plantings/actions', planting: planting
.float-right= render 'members/location', member: planting.owner .float-right= render 'members/location', member: planting.owner
.card-footer .card-footer
- if crop.approved? - if crop.approved?

View File

@@ -0,0 +1,26 @@
#modelFailedPlantingForm.modal.fade{"aria-hidden" => "true", "aria-labelledby" => "failed-planting-button", role: "dialog", tabindex: "-1"}
.modal-dialog{role: "document"}
.modal-content
.modal-header.text-center
%h4.modal-title.w-100.font-weight-bold Mark #{crop.name} planting as failed
%button.close{"aria-label" => "Close", "data-bs-dismiss" => "modal", type: "button"}
%span{"aria-hidden" => "true"} &#215;
.modal-body
%p Which planting would you like to mark as failed?
%ul.list-group
- active_plantings.each do |planting|
%li.list-group-item
= link_to planting_path(planting, planting: {failed: 1}), method: :put do
.d-flex.justify-content-between
%span
%h4= planting.garden.name
%p Planted #{planting.planted_at}
%span
= finished_icon
.mt-3.text-right
= link_to 'cancel', '', "data-bs-dismiss" => "modal", class: 'btn btn-secondary'
%a.btn#failed-planting-button{"data-bs-target" => "#modelFailedPlantingForm", "data-bs-toggle" => "modal", href: ""}
= finished_icon
Mark as failed

View File

@@ -62,9 +62,9 @@ module Growstuff
# Growstuff-specific configuration variables # Growstuff-specific configuration variables
config.currency = 'AUD' config.currency = 'AUD'
config.bot_email = ENV.fetch('GROWSTUFF_EMAIL', nil) config.bot_email = Rails.configuration.x.email[:from]
config.user_agent = 'Growstuff' config.user_agent = 'Growstuff'
config.user_agent_email = "info@growstuff.org" config.user_agent_email = Rails.configuration.x.email[:from]
Gibbon::API.api_key = ENV['GROWSTUFF_MAILCHIMP_APIKEY'] || 'notarealkey' Gibbon::API.api_key = ENV['GROWSTUFF_MAILCHIMP_APIKEY'] || 'notarealkey'
# API key can't be blank or tests fail # API key can't be blank or tests fail

View File

@@ -6,7 +6,7 @@ Devise.setup do |config|
# ==> Mailer Configuration # ==> Mailer Configuration
# Configure the e-mail address which will be shown in Devise::Mailer, # Configure the e-mail address which will be shown in Devise::Mailer,
# note that it will be overwritten if you use your own mailer class with default "from" parameter. # note that it will be overwritten if you use your own mailer class with default "from" parameter.
config.mailer_sender = "Growstuff <#{ENV.fetch('GROWSTUFF_EMAIL', nil)}>" config.mailer_sender = "Growstuff <#{Rails.configuration.x.email[:from]}>"
config.secret_key = ENV.fetch('RAILS_SECRET_TOKEN', nil) config.secret_key = ENV.fetch('RAILS_SECRET_TOKEN', nil)

View File

@@ -0,0 +1,9 @@
module Growstuff
class Application < Rails::Application
config.x.email = {
from: ENV.fetch('GROWSTUFF_EMAIL', 'info@growstuff.org'),
admin: ENV.fetch('GROWSTUFF_ADMIN_EMAIL', 'sysadmin@growstuff.org'),
support: ENV.fetch('GROWSTUFF_SUPPORT_EMAIL', 'info@growstuff.org')
}
end
end

View File

@@ -8,6 +8,6 @@ class CreateBlocks < ActiveRecord::Migration[6.1]
t.timestamps t.timestamps
end end
add_index :blocks, [:blocker_id, :blocked_id], unique: true add_index :blocks, %i(blocker_id blocked_id), unique: true
end end
end end

View File

@@ -49,9 +49,9 @@ describe ForumsController do
let(:valid_attributes) { { name: "New Forum", description: "A new forum", owner_id: admin.id } } let(:valid_attributes) { { name: "New Forum", description: "A new forum", owner_id: admin.id } }
it "creates a new Forum" do it "creates a new Forum" do
expect { expect do
post :create, params: { forum: valid_attributes } post :create, params: { forum: valid_attributes }
}.to change(Forum, :count).by(1) end.to change(Forum, :count).by(1)
end end
it "redirects to the created forum" do it "redirects to the created forum" do
@@ -81,9 +81,9 @@ describe ForumsController do
describe "DELETE #destroy" do describe "DELETE #destroy" do
it "destroys the requested forum" do it "destroys the requested forum" do
forum # ensure forum exists forum # ensure forum exists
expect { expect do
delete :destroy, params: { id: forum.to_param } delete :destroy, params: { id: forum.to_param }
}.to change(Forum, :count).by(-1) end.to change(Forum, :count).by(-1)
end end
it "redirects to the forums list" do it "redirects to the forums list" do

View File

@@ -9,18 +9,18 @@ describe PlacesController do
describe "GET show" do describe "GET show" do
before do before do
@member_london = create(:london_member) @london_member = create(:london_member)
@member_south_pole = create(:south_pole_member) @edinburgh_member = create(:edinburgh_member)
end end
it "assigns place name" do it "assigns place name" do
get :show, params: { place: @member_london.location } get :show, params: { place: @london_member.location }
assigns(:place).should eq @member_london.location assigns(:place).should eq @london_member.location
end end
it "assigns nearby members" do it "assigns nearby members" do
get :show, params: { place: @member_london.location } get :show, params: { place: @london_member.location }
assigns(:nearby_members).should eq [@member_london, @member_south_pole] assigns(:nearby_members).should eq [@london_member, @edinburgh_member]
end end
end end

View File

@@ -18,8 +18,8 @@ describe PlantPart do
@h2 = create(:harvest, @h2 = create(:harvest,
crop: @maize, crop: @maize,
plant_part: @pp1) plant_part: @pp1)
@pp1.crops.should include @tomato expect(@pp1.crops).to include @tomato
@pp1.crops.should include @maize expect(@pp1.crops).to include @maize
end end
it "doesn't duplicate crops" do it "doesn't duplicate crops" do
@@ -31,6 +31,6 @@ describe PlantPart do
@h2 = create(:harvest, @h2 = create(:harvest,
crop: @maize, crop: @maize,
plant_part: @pp1) plant_part: @pp1)
@pp1.crops.should eq [@maize] expect(@pp1.crops).to eq [@maize]
end end
end end

View File

@@ -7,35 +7,35 @@ describe Seed do
let(:seed) { build(:seed, owner:) } let(:seed) { build(:seed, owner:) }
it 'saves a basic seed' do it 'saves a basic seed' do
seed.save.should be(true) expect(seed.save).to be(true)
end end
it "has a slug" do it "has a slug" do
seed.save seed.save
seed.slug.should match(/tamateapokaiwhenua-magic-bean/) expect(seed.slug).to match(/tamateapokaiwhenua-magic-bean/)
end end
context 'quantity' do context 'quantity' do
it 'allows integer quantities' do it 'allows integer quantities' do
@seed = build(:seed, quantity: 99) @seed = build(:seed, quantity: 99)
@seed.should be_valid expect(@seed).to be_valid
end end
it "doesn't allow decimal quantities" do it "doesn't allow decimal quantities" do
@seed = build(:seed, quantity: 99.9) @seed = build(:seed, quantity: 99.9)
@seed.should_not be_valid expect(@seed).not_to be_valid
end end
it "doesn't allow non-numeric quantities" do it "doesn't allow non-numeric quantities" do
@seed = build(:seed, quantity: 'foo') @seed = build(:seed, quantity: 'foo')
@seed.should_not be_valid expect(@seed).not_to be_valid
end end
it "allows blank quantities" do it "allows blank quantities" do
@seed = build(:seed, quantity: nil) @seed = build(:seed, quantity: nil)
@seed.should be_valid expect(@seed).to be_valid
@seed = build(:seed, quantity: '') @seed = build(:seed, quantity: '')
@seed.should be_valid expect(@seed).to be_valid
end end
end end
@@ -43,14 +43,14 @@ describe Seed do
it 'all valid tradable_to values should work' do it 'all valid tradable_to values should work' do
%w(nowhere locally nationally internationally).each do |t| %w(nowhere locally nationally internationally).each do |t|
@seed = build(:seed, tradable_to: t) @seed = build(:seed, tradable_to: t)
@seed.should be_valid expect(@seed).to be_valid
end end
end end
it 'refuses invalid tradable_to values' do it 'refuses invalid tradable_to values' do
@seed = build(:seed, tradable_to: 'not valid') @seed = build(:seed, tradable_to: 'not valid')
@seed.should_not be_valid expect(@seed).not_to be_valid
@seed.errors[:tradable_to].should include( expect(@seed.errors[:tradable_to]).to include(
"You may only trade seed nowhere, locally, " \ "You may only trade seed nowhere, locally, " \
"nationally, or internationally" "nationally, or internationally"
) )
@@ -58,35 +58,35 @@ describe Seed do
it 'does not allow nil or blank values' do it 'does not allow nil or blank values' do
@seed = build(:seed, tradable_to: nil) @seed = build(:seed, tradable_to: nil)
@seed.should_not be_valid expect(@seed).not_to be_valid
@seed = build(:seed, tradable_to: '') @seed = build(:seed, tradable_to: '')
@seed.should_not be_valid expect(@seed).not_to be_valid
end end
it 'tradable gives the right answers' do it 'tradable gives the right answers' do
@seed = create(:seed, tradable_to: 'nowhere') @seed = create(:seed, tradable_to: 'nowhere')
@seed.tradable.should be false expect(@seed.tradable).to be false
@seed = create(:seed, tradable_to: 'locally') @seed = create(:seed, tradable_to: 'locally')
@seed.tradable.should be true expect(@seed.tradable).to be true
@seed = create(:seed, tradable_to: 'nationally') @seed = create(:seed, tradable_to: 'nationally')
@seed.tradable.should be true expect(@seed.tradable).to be true
@seed = create(:seed, tradable_to: 'internationally') @seed = create(:seed, tradable_to: 'internationally')
@seed.tradable.should be true expect(@seed.tradable).to be true
end end
it 'recognises a tradable seed' do it 'recognises a tradable seed' do
create(:tradable_seed).tradable.should == true expect(create(:tradable_seed).tradable).to be true
end end
it 'recognises an untradable seed' do it 'recognises an untradable seed' do
create(:untradable_seed).tradable.should == false expect(create(:untradable_seed).tradable).to be false
end end
it 'scopes correctly' do it 'scopes correctly' do
@tradable = create(:tradable_seed) @tradable = create(:tradable_seed)
@untradable = create(:untradable_seed) @untradable = create(:untradable_seed)
described_class.tradable.should include @tradable expect(described_class.tradable).to include @tradable
described_class.tradable.should_not include @untradable expect(described_class.tradable).not_to include @untradable
end end
end end
@@ -95,7 +95,7 @@ describe Seed do
['certified organic', 'non-certified organic', ['certified organic', 'non-certified organic',
'conventional/non-organic', 'unknown'].each do |t| 'conventional/non-organic', 'unknown'].each do |t|
@seed = build(:seed, organic: t) @seed = build(:seed, organic: t)
@seed.should be_valid expect(@seed).to be_valid
end end
end end
@@ -103,31 +103,31 @@ describe Seed do
['certified GMO-free', 'non-certified GMO-free', ['certified GMO-free', 'non-certified GMO-free',
'GMO', 'unknown'].each do |t| 'GMO', 'unknown'].each do |t|
@seed = build(:seed, gmo: t) @seed = build(:seed, gmo: t)
@seed.should be_valid expect(@seed).to be_valid
end end
end end
it 'all valid heirloom values should work' do it 'all valid heirloom values should work' do
%w(heirloom hybrid unknown).each do |t| %w(heirloom hybrid unknown).each do |t|
@seed = build(:seed, heirloom: t) @seed = build(:seed, heirloom: t)
@seed.should be_valid expect(@seed).to be_valid
end end
end end
it 'refuses invalid organic/GMO/heirloom values' do it 'refuses invalid organic/GMO/heirloom values' do
%i(organic gmo heirloom).each do |field| %i(organic gmo heirloom).each do |field|
@seed = build(:seed, field => 'not valid') @seed = build(:seed, field => 'not valid')
@seed.should_not be_valid expect(@seed).not_to be_valid
@seed.errors[field].should_not be_empty expect(@seed.errors[field]).not_to be_empty
end end
end end
it 'does not allow nil or blank values' do it 'does not allow nil or blank values' do
%i(organic gmo heirloom).each do |field| %i(organic gmo heirloom).each do |field|
@seed = build(:seed, field => nil) @seed = build(:seed, field => nil)
@seed.should_not be_valid expect(@seed).not_to be_valid
@seed = build(:seed, field => '') @seed = build(:seed, field => '')
@seed.should_not be_valid expect(@seed).not_to be_valid
end end
end end
end end
@@ -136,13 +136,13 @@ describe Seed do
it 'returns seeds with a plant_before date in the past' do it 'returns seeds with a plant_before date in the past' do
expired_seed = create(:seed, plant_before: 1.day.ago) expired_seed = create(:seed, plant_before: 1.day.ago)
not_expired_seed = create(:seed, plant_before: 1.day.from_now) not_expired_seed = create(:seed, plant_before: 1.day.from_now)
described_class.expired.should include expired_seed expect(described_class.expired).to include expired_seed
described_class.expired.should_not include not_expired_seed expect(described_class.expired).not_to include not_expired_seed
end end
it 'does not return finished seeds' do it 'does not return finished seeds' do
expired_seed = create(:seed, plant_before: 1.day.ago, finished: true) expired_seed = create(:seed, plant_before: 1.day.ago, finished: true)
described_class.expired.should_not include expired_seed expect(described_class.expired).not_to include expired_seed
end end
end end
@@ -158,11 +158,11 @@ describe Seed do
@seed3 = create(:tradable_seed) @seed3 = create(:tradable_seed)
@seed4 = create(:seed) @seed4 = create(:seed)
described_class.interesting.should include @seed1 expect(described_class.interesting).to include @seed1
described_class.interesting.should_not include @seed2 expect(described_class.interesting).not_to include @seed2
described_class.interesting.should_not include @seed3 expect(described_class.interesting).not_to include @seed3
described_class.interesting.should_not include @seed4 expect(described_class.interesting).not_to include @seed4
described_class.interesting.size.should == 1 expect(described_class.interesting.size).to eq 1
end end
end end
@@ -172,7 +172,7 @@ describe Seed do
before { seed.photos << create(:photo, owner: seed.owner) } before { seed.photos << create(:photo, owner: seed.owner) }
it 'is found in has_photos scope' do it 'is found in has_photos scope' do
described_class.has_photos.should include(seed) expect(described_class.has_photos).to include(seed)
end end
end end

View File

@@ -37,9 +37,9 @@ describe "Forums" do
before { sign_in admin } before { sign_in admin }
it "creates a new forum" do it "creates a new forum" do
expect { expect do
post forums_path, params: { forum: { name: "New Request Forum", description: "Desc", owner_id: admin.id } } post forums_path, params: { forum: { name: "New Request Forum", description: "Desc", owner_id: admin.id } }
}.to change(Forum, :count).by(1) end.to change(Forum, :count).by(1)
expect(response).to redirect_to(forum_path(Forum.last)) expect(response).to redirect_to(forum_path(Forum.last))
end end
end end

View File

@@ -15,11 +15,11 @@ describe 'comments/index.rss.haml' do
end end
it 'shows RSS feed title' do it 'shows RSS feed title' do
rendered.should have_content "Recent comments on all posts" expect(rendered).to have_content "Recent comments on all posts"
end end
it 'shows item title' do it 'shows item title' do
rendered.should have_content "Comment by #{@author.login_name}" expect(rendered).to have_content "Comment by #{@author.login_name}"
end end
it 'escapes html for link to post' do it 'escapes html for link to post' do
@@ -28,6 +28,6 @@ describe 'comments/index.rss.haml' do
end end
it 'shows content of comments' do it 'shows content of comments' do
rendered.should have_content "OMG LOL" expect(rendered).to have_content "OMG LOL"
end end
end end

View File

@@ -13,7 +13,7 @@ describe "crops/_grown_for" do
it 'shows plant parts' do it 'shows plant parts' do
render partial: 'crops/grown_for', locals: { crop: } render partial: 'crops/grown_for', locals: { crop: }
rendered.should have_content plant_path.name expect(rendered).to have_content plant_path.name
assert_select "a", href: plant_part_path(plant_path) assert_select "a", href: plant_part_path(plant_path)
end end
end end

View File

@@ -12,10 +12,10 @@ describe "crops/_popover" do
end end
it 'has a scientific name' do it 'has a scientific name' do
rendered.should have_content 'Solanum lycopersicum' expect(rendered).to have_content 'Solanum lycopersicum'
end end
it 'shows count of plantings' do it 'shows count of plantings' do
rendered.should have_content '1 time' expect(rendered).to have_content '1 time'
end end
end end

View File

@@ -33,7 +33,7 @@ describe "crops/index.html.haml" do
context "downloads" do context "downloads" do
it "offers data downloads" do it "offers data downloads" do
render render
rendered.should have_content "The data on this page is available in the following formats:" expect(rendered).to have_content "The data on this page is available in the following formats:"
assert_select "a", href: crops_path(format: 'csv') assert_select "a", href: crops_path(format: 'csv')
assert_select "a", href: crops_path(format: 'json') assert_select "a", href: crops_path(format: 'json')
assert_select "a", href: crops_path(format: 'rss') assert_select "a", href: crops_path(format: 'rss')

View File

@@ -13,11 +13,11 @@ describe 'crops/index.rss.haml' do
end end
it 'shows RSS feed title' do it 'shows RSS feed title' do
rendered.should have_content "Recently added crops" expect(rendered).to have_content "Recently added crops"
end end
it 'shows names of crops' do it 'shows names of crops' do
rendered.should have_content @tomato.name expect(rendered).to have_content @tomato.name
rendered.should have_content @maize.name expect(rendered).to have_content @maize.name
end end
end end

View File

@@ -10,6 +10,6 @@ describe 'devise/confirmations/new.html.haml', type: "view" do
end end
it 'contains a login field' do it 'contains a login field' do
rendered.should have_content "Enter either your login name or your email address" expect(rendered).to have_content "Enter either your login name or your email address"
end end
end end

View File

@@ -10,11 +10,11 @@ describe 'devise/mailer/confirmation_instructions.html.haml', type: "view" do
end end
it 'has a confirmation link' do it 'has a confirmation link' do
rendered.should have_content 'Confirm my account' expect(rendered).to have_content 'Confirm my account'
end end
it 'has a link to the homepage' do it 'has a link to the homepage' do
rendered.should have_content root_url expect(rendered).to have_content root_url
end end
end end
end end

View File

@@ -12,8 +12,8 @@ describe 'devise/mailer/reset_password_instructions.html.haml', type: "view" do
end end
it 'has some of the right text' do it 'has some of the right text' do
rendered.should have_content 'Change my password' expect(rendered).to have_content 'Change my password'
rendered.should have_content 'Someone has requested a link to reset your password' expect(rendered).to have_content 'Someone has requested a link to reset your password'
end end
end end
end end

View File

@@ -9,11 +9,11 @@ describe 'devise/mailer/unlock_instructions.html.haml', type: "view" do
end end
it "explains what's happened" do it "explains what's happened" do
rendered.should have_content "account has been locked" expect(rendered).to have_content "account has been locked"
end end
it "has an unlock link" do it "has an unlock link" do
rendered.should have_content "Unlock my account" expect(rendered).to have_content "Unlock my account"
end end
end end
end end

View File

@@ -16,7 +16,7 @@ describe 'devise/registrations/edit.html.haml', type: "view" do
it 'has some fields' do it 'has some fields' do
render render
rendered.should have_content 'Email' expect(rendered).to have_content 'Email'
end end
context 'email section' do context 'email section' do

View File

@@ -13,7 +13,7 @@ describe 'devise/registrations/new.html.haml', type: "view" do
end end
it 'has some fields' do it 'has some fields' do
rendered.should have_content 'Email' expect(rendered).to have_content 'Email'
end end
it 'has a checkbox for newsletter subscription' do it 'has a checkbox for newsletter subscription' do

View File

@@ -13,8 +13,8 @@ describe 'devise/sessions/new.html.haml', type: "view" do
end end
it 'has some fields' do it 'has some fields' do
rendered.should have_content 'Remember me' expect(rendered).to have_content 'Remember me'
rendered.should have_content 'Password' expect(rendered).to have_content 'Password'
end end
end end
end end

View File

@@ -10,7 +10,7 @@ describe 'home/_blurb.html.haml', type: "view" do
end end
it 'has description' do it 'has description' do
rendered.should have_content 'is a community of food gardeners' expect(rendered).to have_content 'is a community of food gardeners'
end end
it 'has signup section' do it 'has signup section' do
@@ -19,7 +19,7 @@ describe 'home/_blurb.html.haml', type: "view" do
end end
it 'has a link to sign in' do it 'has a link to sign in' do
rendered.should have_content "Or sign in if you already have an account" expect(rendered).to have_content "Or sign in if you already have an account"
assert_select "a", href: new_member_session_path assert_select "a", href: new_member_session_path
end end
end end

View File

@@ -5,6 +5,6 @@ require 'rails_helper'
describe 'home/_stats.html.haml', type: "view" do describe 'home/_stats.html.haml', type: "view" do
it 'has activity stats' do it 'has activity stats' do
render render
rendered.should have_content "So far, 0 members have planted 0 crops" expect(rendered).to have_content "So far, 0 members have planted 0 crops"
end end
end end

View File

@@ -29,8 +29,8 @@ describe 'home/index.html.haml', type: "view" do
end end
it 'show interesting members' do it 'show interesting members' do
rendered.should have_content @member.login_name expect(rendered).to have_content @member.login_name
rendered.should have_content @member.location expect(rendered).to have_content @member.location
end end
end end
end end

View File

@@ -14,24 +14,24 @@ describe 'layouts/_header.html.haml', type: "view" do
end end
it 'has signup/signin links' do it 'has signup/signin links' do
rendered.should have_content 'Sign up' expect(rendered).to have_content 'Sign up'
rendered.should have_content 'Sign in' expect(rendered).to have_content 'Sign in'
end end
it 'has a Crops link' do it 'has a Crops link' do
rendered.should have_content "Crops" expect(rendered).to have_content "Crops"
end end
it 'has a Seeds link' do it 'has a Seeds link' do
rendered.should have_content "Seeds" expect(rendered).to have_content "Seeds"
end end
it 'has a Places link' do it 'has a Places link' do
rendered.should have_content "Community Map" expect(rendered).to have_content "Community Map"
end end
it 'has a Community section' do it 'has a Community section' do
rendered.should have_content "Community" expect(rendered).to have_content "Community"
end end
it 'links to members' do it 'links to members' do
@@ -62,7 +62,7 @@ describe 'layouts/_header.html.haml', type: "view" do
context "login name" do context "login name" do
it 'has member login name' do it 'has member login name' do
rendered.should have_content @member.login_name.to_s expect(rendered).to have_content @member.login_name.to_s
end end
it "shows link to member's gardens" do it "shows link to member's gardens" do
@@ -83,19 +83,19 @@ describe 'layouts/_header.html.haml', type: "view" do
end end
it 'shows signout link' do it 'shows signout link' do
rendered.should have_content 'Sign out' expect(rendered).to have_content 'Sign out'
end end
it 'shows inbox link' do it 'shows inbox link' do
rendered.should have_content 'Inbox' expect(rendered).to have_content 'Inbox'
rendered.should_not match(/Inbox \d+/) expect(rendered).not_to match(/Inbox \d+/)
end end
context 'has notifications' do context 'has notifications' do
it 'shows inbox count' do it 'shows inbox count' do
create(:notification, recipient: @member) create(:notification, recipient: @member)
render render
rendered.should have_content 'Inbox 1' expect(rendered).to have_content 'Inbox 1'
end end
end end
end end

View File

@@ -11,6 +11,6 @@ describe 'layouts/application.html.haml', type: "view" do
Rails.application.config.analytics_code = '<script>console.log("foo!");</script>' Rails.application.config.analytics_code = '<script>console.log("foo!");</script>'
render render
assert_select "script", text: 'console.log("foo!");' assert_select "script", text: 'console.log("foo!");'
rendered.should_not have_content 'script' expect(rendered).to have_no_content 'script'
end end
end end

View File

@@ -109,7 +109,7 @@ describe "photos/show" do
end end
it "contains the phrase 'All rights reserved'" do it "contains the phrase 'All rights reserved'" do
rendered.should have_content "All rights reserved" expect(rendered).to have_content "All rights reserved"
end end
end end
end end

View File

@@ -22,7 +22,7 @@ describe "places/show" do
it "shows the names of nearby members" do it "shows the names of nearby members" do
@nearby_members.each do |m| @nearby_members.each do |m|
rendered.should have_content m.login_name expect(rendered).to have_content m.login_name
end end
end end
end end

View File

@@ -45,7 +45,7 @@ describe "plantings/index.html.haml" do
it "provides data links" do it "provides data links" do
render render
rendered.should have_content "The data on this page is available in the following formats:" expect(rendered).to have_content "The data on this page is available in the following formats:"
assert_select "a", href: plantings_path(format: 'csv') assert_select "a", href: plantings_path(format: 'csv')
assert_select "a", href: plantings_path(format: 'json') assert_select "a", href: plantings_path(format: 'json')
assert_select "a", href: plantings_path(format: 'rss') assert_select "a", href: plantings_path(format: 'rss')

View File

@@ -54,11 +54,11 @@ describe "posts/_single" do
end end
it "shows edited at" do it "shows edited at" do
rendered.should have_content "edited at" expect(rendered).to have_content "edited at"
end end
it "shows the updated time" do it "shows the updated time" do
rendered.should have_content @post.updated_at.to_fs(:default) expect(rendered).to have_content @post.updated_at.to_fs(:default)
end end
end end
@@ -74,11 +74,11 @@ describe "posts/_single" do
end end
it "shows edited at time" do it "shows edited at time" do
rendered.should have_content "edited at" expect(rendered).to have_content "edited at"
end end
it "shows updated time" do it "shows updated time" do
rendered.should have_content @comment.updated_at expect(rendered).to have_content @comment.updated_at
end end
end end
@@ -93,7 +93,7 @@ describe "posts/_single" do
end end
it "does not show edited at" do it "does not show edited at" do
rendered.should_not have_content "edited at #{@post.updated_at}" expect(rendered).to have_no_content "edited at #{@post.updated_at}"
end end
end end
@@ -109,7 +109,7 @@ describe "posts/_single" do
end end
it "does not show edited at" do it "does not show edited at" do
rendered.should_not have_content "edited at #{@comment.updated_at}" expect(rendered).to have_no_content "edited at #{@comment.updated_at}"
end end
end end
end end

View File

@@ -27,7 +27,7 @@ describe "posts/edit" do
end end
it 'no forum mentioned' do it 'no forum mentioned' do
rendered.should_not have_content "This post will be posted in the forum" expect(rendered).to have_no_content "This post will be posted in the forum"
end end
context "forum specified" do context "forum specified" do
@@ -44,7 +44,7 @@ describe "posts/edit" do
end end
it 'tells the user what forum it will be posted in' do it 'tells the user what forum it will be posted in' do
rendered.should have_content "This post will be posted in the forum #{@forum.name}" expect(rendered).to have_content "This post will be posted in the forum #{@forum.name}"
end end
end end
end end

View File

@@ -14,19 +14,19 @@ describe 'posts/show.rss.haml' do
end end
it 'shows RSS feed title' do it 'shows RSS feed title' do
rendered.should have_content "Recent comments on #{@post.subject}" expect(rendered).to have_content "Recent comments on #{@post.subject}"
end end
it 'shows item title' do it 'shows item title' do
rendered.should have_content "Comment by #{@author.login_name}" expect(rendered).to have_content "Comment by #{@author.login_name}"
end end
it 'escapes html for link to post' do it 'escapes html for link to post' do
# it's then unescaped by 'render' so we don't actually look for &lt; # it's then unescaped by 'render' so we don't actually look for &lt;
rendered.should have_content '<a href=' expect(rendered).to have_content '<a href='
end end
it 'shows content of comments' do it 'shows content of comments' do
rendered.should have_content "OMG LOL" expect(rendered).to have_content "OMG LOL"
end end
end end