[Rails] Fertilizer recipe solver for the FAPG.
Properly implement bed and raft management logic.
Changed files
- app/controllers/beds_controller.rb
- app/controllers/crops_controller.rb
- app/controllers/rafts_controller.rb
- app/helpers/beds_helper.rb
- app/models/bed.rb
- app/models/raft.rb
- app/views/application/_navbar.html.erb
- app/views/beds/_bed.html.erb
- app/views/beds/_form.html.erb
- app/views/beds/edit.html.erb
- app/views/beds/index.html.erb
- app/views/dashboard/_nutrient_measurements.html.erb
- app/views/dashboard/_raft_allocation.html.erb
- app/views/dashboard/_recent_measurements.html.erb
- app/views/dashboard/index.html.erb
- app/views/rafts/_form.html.erb
- app/views/rafts/edit.html.erb
- app/views/rafts/editor.html.erb
- config/routes.rb
- db/seeds/3_crops.rb
- db/seeds/4_beds_and_rafts.rb
- test/controllers/beds_controller_test.rb
- test/fixtures/beds.yml
- test/system/beds_test.rb
app/controllers/beds_controller.rb
@@ -0,0 +1,61 @@
1
Added:
class BedsController < ApplicationController
2
Added:
before_action :set_bed, only: %i[ edit update ]
3
Added:
before_action :get_crops, only: %i[ index edit update ]
4
Added:
5
Added:
def index
6
Added:
@beds = Bed.all
7
Added:
end
8
Added:
9
Added:
def edit
10
Added:
end
11
Added:
12
Added:
def update
13
Added:
if @bed.update(bed_params)
14
Added:
redirect_to beds_path, notice: "Bed #{@bed.id} successfully updated."
15
Added:
else
16
Added:
render :edit, status: :unprocessable_entity
17
Added:
end
18
Added:
end
19
Added:
20
Added:
def bulk_assign_crops
21
Added:
crop = Crop.find(params[:crop_id])
22
Added:
Raft.update_all(crop_id: crop.id)
23
Added:
redirect_back fallback_location: root_path, notice: "All rafts set to #{crop.name}."
24
Added:
end
25
Added:
26
Added:
27
Added:
def reset_seed_crops
28
Added:
# mirrors seed logic
29
Added:
tomatoes = Crop.find_by!(name: :tomatoes)
30
Added:
chives = Crop.find_by!(name: :chives)
31
Added:
lettuce = Crop.find_by!(name: :lettuce)
32
Added:
33
Added:
Bed.includes(:rafts).find_each do |bed|
34
Added:
default_crop =
35
Added:
case bed.location
36
Added:
when 1..3 then tomatoes
37
Added:
when 4..7 then chives
38
Added:
else lettuce
39
Added:
end
40
Added:
bed.rafts.update_all(crop_id: default_crop.id)
41
Added:
end
42
Added:
redirect_back fallback_location: root_path, notice: "Raft crops reset to default seed layout."
43
Added:
end
44
Added:
45
Added:
private
46
Added:
47
Added:
def set_bed
48
Added:
@bed = Bed.find(params[:id])
49
Added:
end
50
Added:
51
Added:
def get_crops
52
Added:
@crops = Crop.order(:name)
53
Added:
end
54
Added:
55
Added:
def bed_params
56
Added:
params.require(:bed).permit(
57
Added:
:location,
58
Added:
rafts_attributes: %i[id crop_id]
59
Added:
)
60
Added:
end
61
Added:
end
app/controllers/crops_controller.rb
@@ -1,40 +1,30 @@
1
1
class CropsController < ApplicationController
2
2
before_action :set_crop, only: %i[ show edit update destroy ]
3
3
4
Removed:
# GET /crops or /crops.json
5
4
def index
6
5
@crops = Crop.all
7
6
end
8
7
9
Removed:
# GET /crops/1 or /crops/1.json
10
8
def show
11
9
end
12
10
13
Removed:
# GET /crops/new
14
11
def new
15
12
@crop = Crop.new
16
13
end
17
14
18
Removed:
# GET /crops/1/edit
19
15
def edit
20
16
end
21
17
22
Removed:
# POST /crops or /crops.json
23
18
def create
24
19
@crop = Crop.new(crop_params)
25
20
26
Removed:
respond_to do |format|
27
Removed:
if @crop.save
28
Removed:
format.html { redirect_to @crop, notice: "Crop was successfully created." }
29
Removed:
format.json { render :show, status: :created, location: @crop }
30
Removed:
else
31
Removed:
format.html { render :new, status: :unprocessable_entity }
32
Removed:
format.json { render json: @crop.errors, status: :unprocessable_entity }
33
Removed:
end
21
Added:
if @crop.save
22
Added:
redirect_to @crop, notice: "Crop was successfully created."
23
Added:
else
24
Added:
render :new, status: :unprocessable_entity
34
25
end
35
26
end
36
27
37
Removed:
# PATCH/PUT /crops/1 or /crops/1.json
38
28
def update
39
29
respond_to do |format|
40
30
if @crop.update(crop_params)
@@ -47,7 +37,6 @@
47
37
end
48
38
end
49
39
50
Removed:
# DELETE /crops/1 or /crops/1.json
51
40
def destroy
52
41
@crop.destroy!
53
42
@@ -58,13 +47,12 @@
58
47
end
59
48
60
49
private
61
Removed:
# Use callbacks to share common setup or constraints between actions.
62
Removed:
def set_crop
63
Removed:
@crop = Crop.find(params.expect(:id))
64
Removed:
end
65
50
66
Removed:
# Only allow a list of trusted parameters through.
67
Removed:
def crop_params
68
Removed:
params.expect(crop: [ :name, :crop_type, :nno3, :p, :k, :ca, :mg, :s, :na, :cl, :si, :fe, :zn, :b, :mn, :cu, :mo, :nnh4 ])
69
Removed:
end
51
Added:
def set_crop
52
Added:
@crop = Crop.find(params.expect(:id))
53
Added:
end
54
Added:
55
Added:
def crop_params
56
Added:
params.expect(crop: [ :name, :crop_type, :nno3, :p, :k, :ca, :mg, :s, :na, :cl, :si, :fe, :zn, :b, :mn, :cu, :mo, :nnh4 ])
57
Added:
end
70
58
end
app/controllers/rafts_controller.rb
@@ -1,54 +1,29 @@
1
1
class RaftsController < ApplicationController
2
Removed:
before_action :set_collections, only: [ :editor ]
2
Added:
before_action :set_raft, only: %i[ edit update ]
3
Added:
before_action :set_crop, only: %i[ edit update ]
3
4
4
Removed:
def index
5
Removed:
redirect_to editor_rafts_path
5
Added:
def edit
6
6
end
7
7
8
Removed:
def editor
9
Removed:
# @beds, @crops set in before_action
10
Removed:
end
11
Removed:
12
Removed:
# 1) Assign ALL rafts
13
Removed:
def assign_all
14
Removed:
crop_id = normalized_crop_id(params[:crop_id])
15
Removed:
Raft.update_all(crop_id: crop_id) # nil ok
16
Removed:
redirect_to editor_rafts_path, notice: "All rafts updated."
17
Removed:
end
18
Removed:
19
Removed:
# 2) Assign all rafts in ONE bed
20
Removed:
def assign_bed
21
Removed:
bed = Bed.find(params.require(:bed_id))
22
Removed:
crop_id = normalized_crop_id(params[:crop_id])
23
Removed:
bed.rafts.update_all(crop_id: crop_id)
24
Removed:
redirect_to editor_rafts_path, notice: "Bed ##{bed.location} updated."
25
Removed:
end
26
Removed:
27
Removed:
# 3) Assign ONE raft
28
Removed:
def assign_one
29
Removed:
raft = Raft.find(params[:id])
30
Removed:
val = params[:crop_id].to_s
31
Removed:
32
Removed:
if val.blank? || val.casecmp("null").zero?
33
Removed:
# Skip validations; write NULL directly
34
Removed:
raft.update_column(:crop_id, nil)
8
Added:
def update
9
Added:
if @raft.update(raft_params)
10
Added:
redirect_to beds_path, notice: "Raft #{@raft.id} successfully updated."
35
11
else
36
Removed:
raft.update!(crop_id: val)
12
Added:
render :edit, status: :unprocessable_entity
37
13
end
38
Removed:
39
Removed:
redirect_to editor_rafts_path(anchor: "bed-#{raft.bed_id}"), notice: "Raft updated."
40
14
end
41
15
42
16
private
43
17
44
Removed:
def set_collections
45
Removed:
@beds = Bed.order(:location)
18
Added:
def set_raft
19
Added:
@raft = Raft.find(params[:id])
20
Added:
end
21
Added:
22
Added:
def set_crop
46
23
@crops = Crop.order(:name)
47
24
end
48
25
49
Removed:
# Accept "", "null" → nil to allow clearing
50
Removed:
def normalized_crop_id(val)
51
Removed:
return nil if val.blank? || val.to_s.downcase == "null"
52
Removed:
val
26
Added:
def raft_params
27
Added:
params.require(:raft).permit(:location, :bed_id, :crop_id)
53
28
end
54
29
end
app/helpers/beds_helper.rb
@@ -0,0 +1,2 @@
1
Added:
module BedsHelper
2
Added:
end
app/models/bed.rb
@@ -1,4 +1,5 @@
1
1
class Bed < ApplicationRecord
2
2
has_many :rafts, -> { order(:location) }, dependent: :destroy
3
Added:
accepts_nested_attributes_for :rafts
3
4
validates :location, presence: true, uniqueness: true
4
5
end
app/models/raft.rb
@@ -1,5 +1,5 @@
1
1
class Raft < ApplicationRecord
2
2
belongs_to :bed
3
Removed:
belongs_to :crop
3
Added:
belongs_to :crop, optional: true
4
4
validates :location, presence: true, uniqueness: { scope: :bed_id }
5
5
end
app/views/application/_navbar.html.erb
@@ -3,12 +3,12 @@
3
3
<span class="navbar-brand">FAPG</span>
4
4
5
5
<button class="navbar-toggler"
6
Removed:
type="button"
7
Removed:
data-bs-toggle="collapse"
8
Removed:
data-bs-target="#navbarSupportedContent"
9
Removed:
aria-controls="navbarSupportedContent"
10
Removed:
aria-expanded="false"
11
Removed:
aria-label="Toggle navigation">
6
Added:
type="button"
7
Added:
data-bs-toggle="collapse"
8
Added:
data-bs-target="#navbarSupportedContent"
9
Added:
aria-controls="navbarSupportedContent"
10
Added:
aria-expanded="false"
11
Added:
aria-label="Toggle navigation">
12
12
<span class="navbar-toggler-icon"></span>
13
13
</button>
14
14
app/views/beds/_bed.html.erb
@@ -0,0 +1,2 @@
1
Added:
<div id="<%= dom_id bed %>">
2
Added:
</div>
app/views/beds/_form.html.erb
@@ -0,0 +1,28 @@
1
Added:
<%= form_with(model: bed) do |form| %>
2
Added:
<% if bed.errors.any? %>
3
Added:
<div style="color: red">
4
Added:
<h2><%= pluralize(bed.errors.count, "error") %> prohibited this bed from being saved:</h2>
5
Added:
<ul>
6
Added:
<% bed.errors.each do |error| %>
7
Added:
<li><%= error.full_message %></li>
8
Added:
<% end %>
9
Added:
</ul>
10
Added:
</div>
11
Added:
<% end %>
12
Added:
13
Added:
<div class="my-3">
14
Added:
<%= form.fields_for :rafts do |raft| %>
15
Added:
<div class="input-group input-group-sm my-2">
16
Added:
<span class="input-group-text">Raft <%= raft.object.location %></span>
17
Added:
<%= raft.collection_select :crop_id, @crops, :id, :name,
18
Added:
{ include_blank: "Unassigned" },
19
Added:
{ class: "form-select" } %>
20
Added:
</div>
21
Added:
<%= raft.hidden_field :id %>
22
Added:
<% end %>
23
Added:
</div>
24
Added:
25
Added:
<div>
26
Added:
<%= form.submit class: "btn btn-primary" %>
27
Added:
</div>
28
Added:
<% end %>
app/views/beds/edit.html.erb
@@ -0,0 +1,11 @@
1
Added:
<% content_for :title, "Editing bed #{@bed.location}" %>
2
Added:
3
Added:
<h1 class="display-1">Editing bed <%= @bed.location %></h1>
4
Added:
5
Added:
<%= render "form", bed: @bed %>
6
Added:
7
Added:
<br>
8
Added:
9
Added:
<div>
10
Added:
<%= link_to "Back to beds", beds_path, class: "btn btn-secondary" %>
11
Added:
</div>
app/views/beds/index.html.erb
@@ -0,0 +1,54 @@
1
Added:
<% content_for :title, "Crop Allocation" %>
2
Added:
3
Added:
<h1 class="display-1">Beds and Rafts</h1>
4
Added:
5
Added:
<%= link_to "Back to dashboard", root_path, class: "btn btn-outline-secondary my-3" %>
6
Added:
7
Added:
8
Added:
<p>
9
Added:
Click on a bed row or an individual raft to update the corresponding crop.
10
Added:
</p>
11
Added:
12
Added:
<%= form_with url: bulk_assign_crops_beds_path,
13
Added:
method: :patch,
14
Added:
local: true do %>
15
Added:
<div class="btn-group" role="group" aria-label="Raft crop bulk actions">
16
Added:
<select class="form-select" name="crop_id">
17
Added:
<% @crops.each do |crop| %>
18
Added:
<option value="<%= crop.id %>"><%= crop.name.titleize %></option>
19
Added:
<% end %>
20
Added:
</select>
21
Added:
<button type="submit" class="btn btn-outline-primary">Apply to all</button>
22
Added:
</div>
23
Added:
<% end %>
24
Added:
25
Added:
<div class="table-responsive">
26
Added:
<table class="table table-sm small text-center align-middle my-3">
27
Added:
<thead>
28
Added:
<tr>
29
Added:
<th>Bed</th>
30
Added:
<% max_cols = @beds.map { |b| b.rafts.count }.max %>
31
Added:
<% (1..max_cols).each do |i| %>
32
Added:
<th>R<%= i %></th>
33
Added:
<% end %>
34
Added:
</tr>
35
Added:
</thead>
36
Added:
<tbody>
37
Added:
<% @beds.each do |bed| %>
38
Added:
<tr>
39
Added:
<th><%= link_to bed.location, edit_bed_path(bed), class: "btn btn-outline-secondary" %></th>
40
Added:
<% bed.rafts.each do |raft| %>
41
Added:
<td>
42
Added:
<%= link_to (raft&.crop&.name || "—"), edit_raft_path(raft), class: "btn btn-sm" %>
43
Added:
</td>
44
Added:
<% end %>
45
Added:
</tr>
46
Added:
<% end %>
47
Added:
</tbody>
48
Added:
</table>
49
Added:
</div>
50
Added:
51
Added:
<%= button_to "Reset crop allocation", reset_seed_crops_beds_path,
52
Added:
method: :post,
53
Added:
form: { data: { turbo: false } },
54
Added:
class: "btn btn-outline-danger" %>
app/views/dashboard/_nutrient_measurements.html.erb
@@ -0,0 +1,22 @@
1
Added:
<div class="card shadow mb-4">
2
Added:
<div class="card-header d-flex justify-content-between align-items-center">
3
Added:
<h5 class="mb-0">Nutrient Measurements</h5>
4
Added:
<div class="btn-group">
5
Added:
<%#= link_to "Add new measurement", editor_rafts_path, class: "btn btn-sm btn-primary" %>
6
Added:
<%#= link_to "View all", editor_rafts_path, class: "btn btn-sm btn-secondary" %>
7
Added:
</div>
8
Added:
</div>
9
Added:
10
Added:
<div class="card-body p-0">
11
Added:
<div class="container mb-3">
12
Added:
<%= line_chart @npk_measurement_data,
13
Added:
title: "NPK",
14
Added:
ytitle: "Concentration (mg/L)" %>
15
Added:
</div>
16
Added:
<div class="container mb-3">
17
Added:
<%= line_chart @ammonium_measurement_data,
18
Added:
title: "Ammonium",
19
Added:
ytitle: "Concentration (mg/L)" %>
20
Added:
</div>
21
Added:
</div>
22
Added:
</div>
app/views/dashboard/_raft_allocation.html.erb
@@ -1,7 +1,7 @@
1
1
<div class="card shadow mb-4">
2
2
<div class="card-header d-flex justify-content-between align-items-center">
3
Removed:
<h5 class="mb-0">Raft Allocation</h5>
4
Removed:
<%= link_to "Edit raft allocation", editor_rafts_path, class: "btn btn-sm btn-primary" %>
3
Added:
<h5 class="mb-0">Crop Allocation</h5>
4
Added:
<%= link_to "Edit allocation", beds_path, class: "btn btn-sm btn-primary" %>
5
5
</div>
6
6
7
7
<%= bar_chart @raft_data, stacked: true %>
app/views/dashboard/_recent_measurements.html.erb
@@ -1,22 +0,0 @@
1
Removed:
<div class="card shadow mb-4">
2
Removed:
<div class="card-header d-flex justify-content-between align-items-center">
3
Removed:
<h5 class="mb-0">Nutrient Measurements</h5>
4
Removed:
<div class="btn-group">
5
Removed:
<%#= link_to "Add new measurement", editor_rafts_path, class: "btn btn-sm btn-primary" %>
6
Removed:
<%#= link_to "View all", editor_rafts_path, class: "btn btn-sm btn-secondary" %>
7
Removed:
</div>
8
Removed:
</div>
9
Removed:
10
Removed:
<div class="card-body p-0">
11
Removed:
<div class="container mb-3">
12
Removed:
<%= line_chart @npk_measurement_data,
13
Removed:
title: "NPK",
14
Removed:
ytitle: "Concentration (mg/L)" %>
15
Removed:
</div>
16
Removed:
<div class="container mb-3">
17
Removed:
<%= line_chart @ammonium_measurement_data,
18
Removed:
title: "Ammonium",
19
Removed:
ytitle: "Concentration (mg/L)" %>
20
Removed:
</div>
21
Removed:
</div>
22
Removed:
</div>
app/views/dashboard/index.html.erb
@@ -4,4 +4,4 @@
4
4
5
5
<%= render "target_table" %>
6
6
7
Removed:
<%= render "recent_measurements" %>
7
Added:
<%= render "nutrient_measurements" %>
app/views/rafts/_form.html.erb
@@ -0,0 +1,23 @@
1
Added:
<%= form_with(model: raft) do |form| %>
2
Added:
<% if raft.errors.any? %>
3
Added:
<div style="color: red">
4
Added:
<h2><%= pluralize(bed.errors.count, "error") %> prohibited this raft from being saved:</h2>
5
Added:
6
Added:
<ul>
7
Added:
<% raft.errors.each do |error| %>
8
Added:
<li><%= error.full_message %></li>
9
Added:
<% end %>
10
Added:
</ul>
11
Added:
</div>
12
Added:
<% end %>
13
Added:
14
Added:
<div class="my-3">
15
Added:
<label class="form-label">Crop</label>
16
Added:
<%= form.collection_select :crop_id, @crops, :id, :name,
17
Added:
{ include_blank: "Unassigned" }, { class: "form-select" } %>
18
Added:
</div>
19
Added:
20
Added:
<div>
21
Added:
<%= form.submit class: "btn btn-primary" %>
22
Added:
</div>
23
Added:
<% end %>
app/views/rafts/edit.html.erb
@@ -0,0 +1,5 @@
1
Added:
<% content_for :title, "Editing bed #{@raft.bed.location}, raft #{@raft.location}" %>
2
Added:
3
Added:
<h1 class="display-1">Editing bed <%= @raft.bed.location %>, raft <%= @raft.location %></h1>
4
Added:
5
Added:
<%= render "form", raft: @raft %>
app/views/rafts/editor.html.erb
@@ -1,108 +0,0 @@
1
Removed:
<div class="d-flex justify-content-between align-items-center mb-3">
2
Removed:
<h1 class="display-1">Rafts editor</h1>
3
Removed:
<%= link_to "Back to dashboard", root_path, class: "btn btn-outline-secondary" %>
4
Removed:
</div>
5
Removed:
6
Removed:
<!-- Bulk assign all rafts -->
7
Removed:
<div class="card">
8
Removed:
<div class="card-header">Assign ALL rafts</div>
9
Removed:
<div class="card-body">
10
Removed:
<%= form_with url: assign_all_rafts_path, method: :patch, class: "row g-2", data: { turbo: false } do %>
11
Removed:
<div class="col-12 col-md-6">
12
Removed:
<select class="form-select" name="crop_id">
13
Removed:
<option value="">— Unassigned (clear) —</option>
14
Removed:
<% @crops.each do |crop| %>
15
Removed:
<option value="<%= crop.id %>"><%= crop.name %></option>
16
Removed:
<% end %>
17
Removed:
</select>
18
Removed:
</div>
19
Removed:
<div class="col-12 col-md-auto">
20
Removed:
<button class="btn btn-primary">Apply to all</button>
21
Removed:
</div>
22
Removed:
<% end %>
23
Removed:
</div>
24
Removed:
</div>
25
Removed:
26
Removed:
<div class="table-responsive">
27
Removed:
<table class="table table-sm table-striped text-center align-middle my-3">
28
Removed:
<thead>
29
Removed:
<tr>
30
Removed:
<th class="text-start">Bed</th>
31
Removed:
<% max_cols = @beds.map { |b| b.rafts.count }.max %>
32
Removed:
<% (1..max_cols).each do |i| %>
33
Removed:
<th>R<%= i %></th>
34
Removed:
<% end %>
35
Removed:
</tr>
36
Removed:
</thead>
37
Removed:
<tbody>
38
Removed:
<% @beds.each do |bed| %>
39
Removed:
<tr>
40
Removed:
<th><%= bed.location %></th>
41
Removed:
<% bed.rafts.order(:location).each do |raft| %>
42
Removed:
<td>
43
Removed:
<% if raft.crop %>
44
Removed:
<%= raft.crop.name %>
45
Removed:
<% else %>
46
Removed:
—
47
Removed:
<% end %>
48
Removed:
</td>
49
Removed:
<% end %>
50
Removed:
</tr>
51
Removed:
<% end %>
52
Removed:
</tbody>
53
Removed:
</table>
54
Removed:
</div>
55
Removed:
56
Removed:
<!-- Per-bed tables -->
57
Removed:
<% @beds.each do |bed| %>
58
Removed:
<div class="card mb-3" id="bed-<%= bed.id %>">
59
Removed:
<div class="card-header d-flex flex-wrap gap-2 align-items-center">
60
Removed:
<span class="me-auto">Bed <strong>#<%= bed.location %></strong></span>
61
Removed:
<%= form_with url: assign_bed_rafts_path, method: :patch, class: "d-flex gap-2 align-items-center", data: { turbo: false } do %>
62
Removed:
<input type="hidden" name="bed_id" value="<%= bed.id %>">
63
Removed:
<select class="form-select" name="crop_id">
64
Removed:
<option value="">— Unassigned (clear) —</option>
65
Removed:
<% @crops.each do |crop| %>
66
Removed:
<option value="<%= crop.id %>"><%= crop.name %></option>
67
Removed:
<% end %>
68
Removed:
</select>
69
Removed:
<button class="btn btn-primary">Apply</button>
70
Removed:
<% end %>
71
Removed:
</div>
72
Removed:
<div class="card-body p-0">
73
Removed:
<div class="table-responsive">
74
Removed:
<table class="table table-sm mb-0 align-middle">
75
Removed:
<thead class="table-light">
76
Removed:
<tr>
77
Removed:
<th class="text-nowrap text-center">Raft</th>
78
Removed:
<th>Crop</th>
79
Removed:
<th class="text-end">Actions</th>
80
Removed:
</tr>
81
Removed:
</thead>
82
Removed:
<tbody>
83
Removed:
<% bed.rafts.order(:location).each do |raft| %>
84
Removed:
<tr>
85
Removed:
<td class="text-center"><strong><%= raft.location %></strong></td>
86
Removed:
<td style="max-width: 280px;">
87
Removed:
<%= form_with url: assign_one_raft_path(raft), method: :patch, class: "d-flex gap-2", data: { turbo: false } do %>
88
Removed:
<select class="form-select" name="crop_id">
89
Removed:
<option value="">— Unassigned (clear) —</option>
90
Removed:
<% @crops.each do |crop| %>
91
Removed:
<option value="<%= crop.id %>" <%= "selected" if raft.crop_id == crop.id %>><%= crop.name %></option>
92
Removed:
<% end %>
93
Removed:
</select>
94
Removed:
<button class="btn btn-outline-primary">Save</button>
95
Removed:
<% end %>
96
Removed:
</td>
97
Removed:
<td class="text-end">
98
Removed:
<%= button_to "Clear", assign_one_raft_path(raft, crop_id: ""), method: :patch,
99
Removed:
form: { data: { turbo: false } }, class: "btn btn-outline-secondary btn-sm" %>
100
Removed:
</td>
101
Removed:
</tr>
102
Removed:
<% end %>
103
Removed:
</tbody>
104
Removed:
</table>
105
Removed:
</div>
106
Removed:
</div>
107
Removed:
</div>
108
Removed:
<% end %>
config/routes.rb
@@ -2,18 +2,17 @@
2
2
root "dashboard#index"
3
3
4
4
get "ferti_recipe", to: "recipes#show"
5
Removed:
resources :fertilizer_products
6
Removed:
resources :raft_crops, only: [ :update ]
7
Removed:
resources :rafts, only: [ :index ] do
5
Added:
6
Added:
resources :beds, only: [ :index, :edit, :update ] do
8
7
collection do
9
Removed:
get :editor # rafts/editor
10
Removed:
patch :assign_all # bulk assign all rafts
11
Removed:
patch :assign_bed # bulk assign per bed
8
Added:
patch :bulk_assign_crops
9
Added:
post :reset_seed_crops
12
10
end
13
Removed:
member do
14
Removed:
patch :assign_one # per raft
15
Removed:
end
11
Added:
12
Added:
resources :rafts, only: [ :index, :edit, :update ], shallow: true
16
13
end
14
Added:
15
Added:
resources :fertilizer_products
17
16
resources :crops
18
17
resources :nutrient_measurements
19
18
db/seeds/3_crops.rb
@@ -104,17 +104,17 @@
104
104
}
105
105
106
106
[
107
Removed:
[ "lettuce", 0, LEAFY ],
108
Removed:
[ "kale", 0, LEAFY ],
109
Removed:
[ "chinese cabbage", 0, LEAFY ],
110
Removed:
[ "tomatoes", 1, TOMATO ],
111
Removed:
[ "raspberries", 1, RASPBERRY ],
112
Removed:
[ "strawberries", 1, STRAWBERRY ],
113
Removed:
[ "hot peppers", 1, HOT_PEPPER ],
114
Removed:
[ "parsley", 2, HERB ],
115
Removed:
[ "chives", 2, HERB ],
116
Removed:
[ "italian basil", 2, HERB ],
117
Removed:
[ "dill", 2, HERB ]
107
Added:
[ "lettuce", 0, LEAFY ],
108
Added:
[ "kale", 0, LEAFY ],
109
Added:
[ "cabbage, chinese", 0, LEAFY ],
110
Added:
[ "tomatoes", 1, TOMATO ],
111
Added:
[ "raspberries", 1, RASPBERRY ],
112
Added:
[ "strawberries", 1, STRAWBERRY ],
113
Added:
[ "hot peppers", 1, HOT_PEPPER ],
114
Added:
[ "parsley", 2, HERB ],
115
Added:
[ "chives", 2, HERB ],
116
Added:
[ "italian basil", 2, HERB ],
117
Added:
[ "dill", 2, HERB ]
118
118
].each do |name, type, nutrient_requirements|
119
119
Crop.find_or_create_by!(name: name) do |c|
120
120
c.crop_type = type
db/seeds/4_beds_and_rafts.rb
@@ -9,7 +9,7 @@
9
9
when 3 then "hot peppers"
10
10
when 4 then "chives"
11
11
when 5 then "italian basil"
12
Removed:
when 6..7 then "chinese cabbage"
12
Added:
when 6..7 then "cabbage, chinese"
13
13
else "lettuce"
14
14
end
15
15
test/controllers/beds_controller_test.rb
@@ -0,0 +1,48 @@
1
Added:
require "test_helper"
2
Added:
3
Added:
class BedsControllerTest < ActionDispatch::IntegrationTest
4
Added:
setup do
5
Added:
@bed = beds(:one)
6
Added:
end
7
Added:
8
Added:
test "should get index" do
9
Added:
get beds_url
10
Added:
assert_response :success
11
Added:
end
12
Added:
13
Added:
test "should get new" do
14
Added:
get new_bed_url
15
Added:
assert_response :success
16
Added:
end
17
Added:
18
Added:
test "should create bed" do
19
Added:
assert_difference("Bed.count") do
20
Added:
post beds_url, params: { bed: {} }
21
Added:
end
22
Added:
23
Added:
assert_redirected_to bed_url(Bed.last)
24
Added:
end
25
Added:
26
Added:
test "should show bed" do
27
Added:
get bed_url(@bed)
28
Added:
assert_response :success
29
Added:
end
30
Added:
31
Added:
test "should get edit" do
32
Added:
get edit_bed_url(@bed)
33
Added:
assert_response :success
34
Added:
end
35
Added:
36
Added:
test "should update bed" do
37
Added:
patch bed_url(@bed), params: { bed: {} }
38
Added:
assert_redirected_to bed_url(@bed)
39
Added:
end
40
Added:
41
Added:
test "should destroy bed" do
42
Added:
assert_difference("Bed.count", -1) do
43
Added:
delete bed_url(@bed)
44
Added:
end
45
Added:
46
Added:
assert_redirected_to beds_url
47
Added:
end
48
Added:
end
test/fixtures/beds.yml
@@ -1,7 +1,11 @@
1
1
# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
2
2
3
Removed:
one:
4
Removed:
number: 1
5
Removed:
6
Removed:
two:
7
Removed:
number: 1
3
Added:
# This model initially had no columns defined. If you add columns to the
4
Added:
# model remove the "{}" from the fixture names and add the columns immediately
5
Added:
# below each fixture, per the syntax in the comments below
6
Added:
#
7
Added:
one: {}
8
Added:
# column: value
9
Added:
#
10
Added:
two: {}
11
Added:
# column: value
test/system/beds_test.rb
@@ -0,0 +1,39 @@
1
Added:
require "application_system_test_case"
2
Added:
3
Added:
class BedsTest < ApplicationSystemTestCase
4
Added:
setup do
5
Added:
@bed = beds(:one)
6
Added:
end
7
Added:
8
Added:
test "visiting the index" do
9
Added:
visit beds_url
10
Added:
assert_selector "h1", text: "Beds"
11
Added:
end
12
Added:
13
Added:
test "should create bed" do
14
Added:
visit beds_url
15
Added:
click_on "New bed"
16
Added:
17
Added:
click_on "Create Bed"
18
Added:
19
Added:
assert_text "Bed was successfully created"
20
Added:
click_on "Back"
21
Added:
end
22
Added:
23
Added:
test "should update Bed" do
24
Added:
visit bed_url(@bed)
25
Added:
click_on "Edit this bed", match: :first
26
Added:
27
Added:
click_on "Update Bed"
28
Added:
29
Added:
assert_text "Bed was successfully updated"
30
Added:
click_on "Back"
31
Added:
end
32
Added:
33
Added:
test "should destroy Bed" do
34
Added:
visit bed_url(@bed)
35
Added:
click_on "Destroy this bed", match: :first
36
Added:
37
Added:
assert_text "Bed was successfully destroyed"
38
Added:
end
39
Added:
end