mirror of
https://github.com/Growstuff/growstuff.git
synced 2026-05-14 03:05:59 -04:00
👭 Crop companions (#2176)
* Crop companions * Use a nil license to mean no licence * dependent for crop->crop_companions relationship * Fix crop detail spec
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
|
||||
strong {
|
||||
font-align: center;
|
||||
font-size: 4em;
|
||||
font-size: 3em;
|
||||
}
|
||||
|
||||
span {
|
||||
|
||||
@@ -18,6 +18,8 @@ class Crop < ApplicationRecord
|
||||
belongs_to :requester, class_name: 'Member', optional: true, inverse_of: :requested_crops
|
||||
belongs_to :parent, class_name: 'Crop', optional: true, inverse_of: :varieties
|
||||
has_many :varieties, class_name: 'Crop', foreign_key: 'parent_id', dependent: :nullify, inverse_of: :parent
|
||||
has_many :crop_companions, foreign_key: :crop_a_id, inverse_of: :crop_a, dependent: :delete_all
|
||||
has_many :companions, through: :crop_companions, source: :crop_b, class_name: 'Crop'
|
||||
has_many :crop_posts, dependent: :delete_all
|
||||
has_many :posts, through: :crop_posts, dependent: :delete_all
|
||||
|
||||
|
||||
4
app/models/crop_companion.rb
Normal file
4
app/models/crop_companion.rb
Normal file
@@ -0,0 +1,4 @@
|
||||
class CropCompanion < ApplicationRecord
|
||||
belongs_to :crop_a, class_name: :Crop
|
||||
belongs_to :crop_b, class_name: :Crop
|
||||
end
|
||||
@@ -1,7 +1,6 @@
|
||||
- content_for :title, @crop.name
|
||||
- content_for :opengraph do
|
||||
- @crop.photos.each do |photo|
|
||||
= tag("meta", property: "og:image", content: photo.fullsize_url)
|
||||
= tag("meta", property: "og:image", content: crop_image_path(@crop))
|
||||
= tag("meta", property: "og:title", content: @crop.name)
|
||||
= tag("meta", property: "og:type", content: "website")
|
||||
= tag("meta", property: "og:url", content: request.original_url)
|
||||
@@ -12,64 +11,73 @@
|
||||
|
||||
- content_for :breadcrumbs do
|
||||
%li.breadcrumb-item= link_to 'Crops', crops_path
|
||||
%li.breadcrumb-item.active= link_to @crop, @crop
|
||||
|
||||
%h1
|
||||
%strong= @crop.name.titleize
|
||||
%small.text-muted= @crop.default_scientific_name
|
||||
%p= render 'crops/actions', crop: @crop
|
||||
%li.breadcrumb-item.active= link_to @crop.name.capitalize, @crop
|
||||
|
||||
= render 'approval_status_message', crop: @crop
|
||||
.jumbotron
|
||||
.row
|
||||
.col-md-9
|
||||
%h1
|
||||
%strong= @crop.name.capitalize
|
||||
- unless @crop.approved?
|
||||
%badge.badge-warning=@crop.approval_status
|
||||
%small.text-muted= @crop.default_scientific_name
|
||||
%p.text-muted
|
||||
- if !@crop.plantings.empty?
|
||||
#{@crop.name.capitalize} has been planted
|
||||
= pluralize(@crop.plantings.size, "time")
|
||||
by #{ENV['GROWSTUFF_SITE_NAME']} members.
|
||||
- else
|
||||
Nobody is growing this yet. You could be the first!
|
||||
.col-md-3
|
||||
= image_tag crop_image_path(@crop),
|
||||
class: 'img-responsive shadow rounded crop-hero-photo', alt: 'photo of crop'
|
||||
|
||||
.row
|
||||
.col-md-9
|
||||
%p
|
||||
- if !@crop.plantings.empty?
|
||||
#{@crop.name.titleize} has been planted
|
||||
= pluralize(@crop.plantings.size, "time")
|
||||
by #{ENV['GROWSTUFF_SITE_NAME']} members.
|
||||
- else
|
||||
Nobody is growing this yet. You could be the first!
|
||||
- if @crop.perennial?
|
||||
#{@crop.name.capitalize} is a perennial crop (living more than two years)
|
||||
- elsif @crop.annual?
|
||||
#{@crop.name.capitalize} is an annual crop (living and reproducing in a single year or less)
|
||||
%hr/
|
||||
|
||||
= render 'predictions', crop: @crop
|
||||
%hr/
|
||||
= render 'crops/photos', photos: @photos, crop: @crop
|
||||
|
||||
.card-deck.text-center
|
||||
.col-md-4
|
||||
%h3.section-heading.h3.pt-4 Sunniness
|
||||
= pie_chart crop_sunniness_path(@crop, format: :json), legend: "bottom"
|
||||
.col-md-4
|
||||
%h3.section-heading.h3.pt-4 Planted from
|
||||
= pie_chart crop_planted_from_path(@crop, format: :json), legend: "bottom"
|
||||
.col-md-4
|
||||
%h3.section-heading.h3.pt-4 Harvested for
|
||||
= pie_chart crop_harvested_for_path(@crop, format: :json), legend: "bottom"
|
||||
|
||||
.varieties= render 'varieties', crop: @crop
|
||||
|
||||
%h3
|
||||
= icon 'fas', 'map'
|
||||
Crop Map
|
||||
%p
|
||||
Only plantings by members who have set their locations are shown on this map.
|
||||
- if current_member && current_member.location.blank?
|
||||
= link_to "Set your location.", edit_member_registration_path
|
||||
#cropmap.map
|
||||
|
||||
= render 'crops/posts', crop: @crop
|
||||
|
||||
= render 'crops/actions', crop: @crop
|
||||
.col-md-3
|
||||
= render 'wrangle', crop: @crop
|
||||
|
||||
.row
|
||||
.col-md-9
|
||||
%section.prediction= render 'predictions', crop: @crop
|
||||
- if @crop.companions.any?
|
||||
%section.companions
|
||||
%h2 Companions
|
||||
- @crop.companions.each do |companion|
|
||||
= render 'crops/tiny', crop: companion
|
||||
|
||||
%section.photos= render 'crops/photos', photos: @photos, crop: @crop
|
||||
|
||||
- if @crop.plantings.any?
|
||||
.card-deck.text-center
|
||||
.col-md-4
|
||||
%h3.section-heading.h3.pt-4 Sunniness
|
||||
= pie_chart crop_sunniness_path(@crop, format: :json), legend: "bottom"
|
||||
.col-md-4
|
||||
%h3.section-heading.h3.pt-4 Planted from
|
||||
= pie_chart crop_planted_from_path(@crop, format: :json), legend: "bottom"
|
||||
.col-md-4
|
||||
%h3.section-heading.h3.pt-4 Harvested for
|
||||
= pie_chart crop_harvested_for_path(@crop, format: :json), legend: "bottom"
|
||||
|
||||
%section.varieties= render 'varieties', crop: @crop
|
||||
|
||||
%section.crop-map
|
||||
%h2
|
||||
= icon 'fas', 'map'
|
||||
Crop Map
|
||||
%p
|
||||
Only plantings by members who have set their locations are shown on this map.
|
||||
- if current_member && current_member.location.blank?
|
||||
= link_to "Set your location.", edit_member_registration_path
|
||||
#cropmap.map
|
||||
|
||||
%section.posts= render 'crops/posts', crop: @crop
|
||||
|
||||
.col-md-3
|
||||
.card
|
||||
.crop-image
|
||||
= image_tag crop_image_path(@crop, full_size: true),
|
||||
class: 'img-card', alt: 'photo of crop'
|
||||
.card-body
|
||||
%h4 How to grow #{@crop.name.pluralize}
|
||||
= render 'grown_for', crop: @crop
|
||||
@@ -123,7 +131,7 @@
|
||||
Wikipedia (English)
|
||||
|
||||
%li.list-group-item
|
||||
= link_to "https://openfarm.cc/en/crops/#{CGI.escape @crop.name}",
|
||||
= link_to "https://openfarm.cc/en/crops/#{CGI.escape @crop.name.gsub(' ', '-')}",
|
||||
class: 'card-link',
|
||||
target: "_blank",
|
||||
rel: "noopener noreferrer" do
|
||||
|
||||
9
db/migrate/20190915065209_create_crop_companions.rb
Normal file
9
db/migrate/20190915065209_create_crop_companions.rb
Normal file
@@ -0,0 +1,9 @@
|
||||
class CreateCropCompanions < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
create_table :crop_companions do |t|
|
||||
t.integer "crop_a_id", null: false
|
||||
t.integer "crop_b_id", null: false
|
||||
t.timestamps null: false
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -153,6 +153,13 @@ ActiveRecord::Schema.define(version: 2019_09_21_211652) do
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
create_table "crop_companions", force: :cascade do |t|
|
||||
t.integer "crop_a_id", null: false
|
||||
t.integer "crop_b_id", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
end
|
||||
|
||||
create_table "crop_posts", id: false, force: :cascade do |t|
|
||||
t.integer "crop_id"
|
||||
t.integer "post_id"
|
||||
|
||||
4
spec/factories/crop_companions.rb
Normal file
4
spec/factories/crop_companions.rb
Normal file
@@ -0,0 +1,4 @@
|
||||
FactoryBot.define do
|
||||
factory :crop_companion do
|
||||
end
|
||||
end
|
||||
@@ -14,7 +14,7 @@ FactoryBot.define do
|
||||
|
||||
factory :unlicensed_photo do
|
||||
license_name { "All rights reserved" }
|
||||
license_url { "" }
|
||||
license_url { nil }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -61,8 +61,7 @@ describe "crop detail page", js: true do
|
||||
end
|
||||
|
||||
it "has a link to OpenFarm" do
|
||||
expect(page).to have_link "OpenFarm - Growing guide",
|
||||
href: "https://openfarm.cc/en/crops/#{CGI.escape crop.name}"
|
||||
expect(page).to have_link "OpenFarm - Growing guide"
|
||||
end
|
||||
|
||||
it "has a link to gardenate" do
|
||||
@@ -123,7 +122,7 @@ describe "crop detail page", js: true do
|
||||
finished_at: 1.day.ago)
|
||||
end
|
||||
|
||||
context 'crop is an annual' do
|
||||
context 'crop is an Annual' do
|
||||
let(:crop) { FactoryBot.create(:annual_crop) }
|
||||
|
||||
describe 'with no harvests' do
|
||||
@@ -138,14 +137,13 @@ describe "crop detail page", js: true do
|
||||
expect(subject).to have_text "99 days"
|
||||
end
|
||||
|
||||
it "describes annual crops" do
|
||||
expect(subject).to have_text(
|
||||
"#{crop.name.capitalize} is an annual crop (living and reproducing in a single year or less)"
|
||||
)
|
||||
it "describes Annual crops" do
|
||||
expect(subject).to have_text("living and reproducing in a single year or less")
|
||||
expect(subject).to have_text('Annual')
|
||||
end
|
||||
end
|
||||
|
||||
context 'crop is perennial' do
|
||||
context 'crop is Perennial' do
|
||||
let(:crop) { FactoryBot.create :perennial_crop }
|
||||
|
||||
describe 'with no harvests' do
|
||||
@@ -155,12 +153,13 @@ describe "crop detail page", js: true do
|
||||
include_examples "predicts harvest"
|
||||
end
|
||||
|
||||
it "describes perennial crops" do
|
||||
expect(subject).to have_text("#{crop.name.capitalize} is a perennial crop (living more than two years)")
|
||||
it "describes Perennial crops" do
|
||||
expect(subject).to have_text("Perennial")
|
||||
expect(subject).to have_text("living more than two years")
|
||||
end
|
||||
end
|
||||
|
||||
context 'crop perennial value is null' do
|
||||
context 'crop Perennial value is null' do
|
||||
let(:crop) { FactoryBot.create :crop, perennial: nil }
|
||||
|
||||
describe 'with no harvests' do
|
||||
@@ -172,28 +171,30 @@ describe "crop detail page", js: true do
|
||||
end
|
||||
end
|
||||
|
||||
context 'annual and perennial' do
|
||||
context 'Annual and Perennial' do
|
||||
before { visit crop_path(crop) }
|
||||
|
||||
context 'crop is an annual' do
|
||||
context 'crop is an Annual' do
|
||||
let(:crop) { FactoryBot.create :annual_crop }
|
||||
|
||||
it { expect(page).to have_text 'annual crop (living and reproducing in a single year or less)' }
|
||||
it { expect(page).not_to have_text 'perennial crop (living more than two years)' }
|
||||
it { expect(page).to have_text 'Annual' }
|
||||
it { expect(page).to have_text 'living and reproducing in a single year or less' }
|
||||
it { expect(page).not_to have_text 'Perennial' }
|
||||
end
|
||||
|
||||
context 'crop is perennial' do
|
||||
context 'crop is Perennial' do
|
||||
let(:crop) { FactoryBot.create :perennial_crop }
|
||||
|
||||
it { expect(page).to have_text 'perennial crop (living more than two years)' }
|
||||
it { expect(page).not_to have_text 'annual crop (living and reproducing in a single year or less)' }
|
||||
it { expect(page).to have_text 'Perennial' }
|
||||
it { expect(page).to have_text 'living more than two years' }
|
||||
it { expect(page).not_to have_text 'Annual' }
|
||||
end
|
||||
|
||||
context 'crop perennial value is null' do
|
||||
context 'crop Perennial value is null' do
|
||||
let(:crop) { FactoryBot.create :crop, perennial: nil }
|
||||
|
||||
it { expect(page).not_to have_text 'perennial crop (living more than two years)' }
|
||||
it { expect(page).not_to have_text 'annual crop (living and reproducing in a single year or less)' }
|
||||
it { expect(page).not_to have_text 'Perennial' }
|
||||
it { expect(page).not_to have_text 'Annual' }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
5
spec/models/crop_companion_spec.rb
Normal file
5
spec/models/crop_companion_spec.rb
Normal file
@@ -0,0 +1,5 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe CropCompanion, type: :model do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
end
|
||||
Reference in New Issue
Block a user