From 684768ba5c4bda28f407ae612691ca380d5fe689 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sat, 29 Nov 2025 03:40:59 +0000 Subject: [PATCH 1/3] feat: Add YouTube video to crop page This commit introduces the following changes: - Adds an `en_youtube_url` attribute to the `Crop` model to store a URL for an English language YouTube video. - If a `en_youtube_url` is present for a crop, the video is embedded on the crop's show page. - A link is added to the "Learn more" section of the crop's show page to search YouTube for "growing [crop name]". - A helper method is added to extract the video ID from various YouTube URL formats. - A validation is added to the `Crop` model to ensure that the `en_youtube_url` is a valid YouTube URL. --- app/helpers/crops_helper.rb | 8 ++++++++ app/models/crop.rb | 6 ++++++ app/views/crops/show.html.haml | 11 +++++++++++ .../20251128193317_add_en_youtube_url_to_crops.rb | 5 +++++ 4 files changed, 30 insertions(+) create mode 100644 db/migrate/20251128193317_add_en_youtube_url_to_crops.rb diff --git a/app/helpers/crops_helper.rb b/app/helpers/crops_helper.rb index a7f19a60d..19f2a9e48 100644 --- a/app/helpers/crops_helper.rb +++ b/app/helpers/crops_helper.rb @@ -17,4 +17,12 @@ module CropsHelper def crop_ebay_seeds_url(crop) "https://www.ebay.com/sch/i.html?_nkw=#{CGI.escape crop.name}" end + + def youtube_video_id(url) + return unless url + + regex = %r{(?:youtube(?:-nocookie)?\.com/(?:[^/\n\s]+/\S+/|(?:v|e(?:mbed)?)/|\S*?[?&]v=)|youtu\.be/)([a-zA-Z0-9_-]{11})} + match = url.match(regex) + match[1] if match + end end diff --git a/app/models/crop.rb b/app/models/crop.rb index a647c766f..bf1a7bbe7 100644 --- a/app/models/crop.rb +++ b/app/models/crop.rb @@ -55,6 +55,12 @@ class Crop < ApplicationRecord message: 'is not a valid English Wikipedia URL' }, if: :approved? + validates :en_youtube_url, + format: { + with: %r{\A(?:https?://)?(?:www\.)?(?:youtube(?:-nocookie)?\.com/(?:(?:v|e(?:mbed)?)/|\S*?[?&]v=)|youtu\.be/)[a-zA-Z0-9_-]{11}(?:[?&]\S*)?\z}, + message: 'is not a valid YouTube URL' + }, + allow_blank: true validates :name, uniqueness: { scope: :approval_status }, if: :pending? def to_s diff --git a/app/views/crops/show.html.haml b/app/views/crops/show.html.haml index 5ab1525b8..45927a3cf 100644 --- a/app/views/crops/show.html.haml +++ b/app/views/crops/show.html.haml @@ -21,6 +21,10 @@ .col-md-3= render 'wrangle', crop: @crop .row .col-md-9 + - if @crop.en_youtube_url.present? + %section.youtube + .embed-responsive.embed-responsive-16by9 + %iframe.embed-responsive-item{ src: "https://www.youtube.com/embed/#{youtube_video_id(@crop.en_youtube_url)}", allowfullscreen: true } %section.prediction = cute_icon = render 'predictions', crop: @crop @@ -157,3 +161,10 @@ = icon 'fas', 'external-link-alt' Wikihow instructions + %li.list-group-item + = link_to "https://www.youtube.com/results?search_query=#{CGI.escape "growing #{@crop.name}"}", + target: "_blank", + class: 'card-link', + rel: "noopener noreferrer" do + = icon 'fab', 'youtube' + YouTube diff --git a/db/migrate/20251128193317_add_en_youtube_url_to_crops.rb b/db/migrate/20251128193317_add_en_youtube_url_to_crops.rb new file mode 100644 index 000000000..bd0cb8e40 --- /dev/null +++ b/db/migrate/20251128193317_add_en_youtube_url_to_crops.rb @@ -0,0 +1,5 @@ +class AddEnYoutubeUrlToCrops < ActiveRecord::Migration[7.2] + def change + add_column :crops, :en_youtube_url, :string + end +end From 73c71584548afc8ba17f57198f7f51b4c11d9cf7 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sat, 29 Nov 2025 03:45:23 +0000 Subject: [PATCH 2/3] feat: Add YouTube video to crop page This commit introduces the following changes: - Adds an `en_youtube_url` attribute to the `Crop` model to store a URL for an English language YouTube video. - The `en_youtube_url` is now an editable field in the crop form. - If a `en_youtube_url` is present for a crop, the video is embedded on the crop's show page. - A link is added to the "Learn more" section of the crop's show page to search YouTube for "growing [crop name]". - A helper method is added to extract the video ID from various YouTube URL formats. - A validation is added to the `Crop` model to ensure that the `en_youtube_url` is a valid YouTube URL. --- app/controllers/crops_controller.rb | 2 +- app/views/crops/_form.html.haml | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/controllers/crops_controller.rb b/app/controllers/crops_controller.rb index 8a76566d0..5b8156269 100644 --- a/app/controllers/crops_controller.rb +++ b/app/controllers/crops_controller.rb @@ -188,7 +188,7 @@ class CropsController < ApplicationController def crop_params params.require(:crop).permit( - :name, :en_wikipedia_url, + :name, :en_wikipedia_url, :en_youtube_url, :parent_id, :perennial, :request_notes, :reason_for_rejection, :rejection_notes, diff --git a/app/views/crops/_form.html.haml b/app/views/crops/_form.html.haml index 8797bfe81..85712c9f5 100644 --- a/app/views/crops/_form.html.haml +++ b/app/views/crops/_form.html.haml @@ -54,6 +54,9 @@ = f.url_field :en_wikipedia_url, id: "en_wikipedia_url", label: 'Wikipedia URL' %span.help-block Link to the crop's page on the English language Wikipedia (required). + = f.url_field :en_youtube_url, label: 'YouTube URL' + %span.help-block + Link to a YouTube video about the crop in English. -# Only crop wranglers see the crop hierarchy (for now) - if can? :wrangle, @crop From e0aaa9e44f32ace8abb06f9a317676800b8e3996 Mon Sep 17 00:00:00 2001 From: Daniel O'Connor Date: Sat, 29 Nov 2025 14:26:15 +1030 Subject: [PATCH 3/3] Rearrange --- app/views/crops/show.html.haml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/views/crops/show.html.haml b/app/views/crops/show.html.haml index 45927a3cf..a2f0fe88a 100644 --- a/app/views/crops/show.html.haml +++ b/app/views/crops/show.html.haml @@ -21,10 +21,6 @@ .col-md-3= render 'wrangle', crop: @crop .row .col-md-9 - - if @crop.en_youtube_url.present? - %section.youtube - .embed-responsive.embed-responsive-16by9 - %iframe.embed-responsive-item{ src: "https://www.youtube.com/embed/#{youtube_video_id(@crop.en_youtube_url)}", allowfullscreen: true } %section.prediction = cute_icon = render 'predictions', crop: @crop @@ -34,6 +30,11 @@ - @crop.all_companions.each do |companion| = render 'crops/tiny', crop: companion + - if @crop.en_youtube_url.present? + %section.youtube + .embed-responsive.embed-responsive-16by9 + %iframe.embed-responsive-item{ src: "https://www.youtube.com/embed/#{youtube_video_id(@crop.en_youtube_url)}", allowfullscreen: true } + %section.photos = cute_icon = render 'crops/photos', crop: @crop