Skip to content

Commit ff372b9

Browse files
authored
Create story ideas crud (#314)
1 parent cd05e3e commit ff372b9

21 files changed

+898
-24
lines changed
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
class StoryIdeasController < ApplicationController
2+
before_action :set_story, only: [:show, :edit, :update, :destroy]
3+
4+
def index
5+
per_page = params[:number_of_items_per_page].presence || 25
6+
7+
8+
story_ideas = StoryIdea.includes(:windows_type, :project, :workshop, :created_by, :updated_by)
9+
@story_ideas = story_ideas.order(created_at: :desc)
10+
.paginate(page: params[:page], per_page: per_page)
11+
12+
@story_ideas_count = story_ideas.size
13+
end
14+
15+
def show
16+
end
17+
18+
def new
19+
@story_idea = StoryIdea.new
20+
set_form_variables
21+
end
22+
23+
def edit
24+
set_form_variables
25+
end
26+
27+
def create
28+
@story_idea = StoryIdea.new(story_idea_params)
29+
30+
if @story_idea.save
31+
redirect_to story_ideas_path, notice: "StoryIdea was successfully created."
32+
else
33+
set_form_variables
34+
render :new, status: :unprocessable_content
35+
end
36+
end
37+
38+
def update
39+
if @story_idea.update(story_idea_params.except(:images))
40+
# Attach new images *in addition* to existing ones
41+
if story_idea_params[:images].present?
42+
@story_idea.images.attach(story_idea_params[:images])
43+
end
44+
redirect_to story_ideas_path, notice: "StoryIdea was successfully updated.", status: :see_other
45+
else
46+
set_form_variables
47+
render :edit, status: :unprocessable_content
48+
end
49+
end
50+
51+
def destroy
52+
@story_idea.destroy!
53+
redirect_to story_ideas_path, notice: "StoryIdea was successfully destroyed."
54+
end
55+
56+
# Optional hooks for setting variables for forms or index
57+
def set_form_variables
58+
@user = User.find(params[:user_id]) if params[:user_id].present?
59+
@projects = (@user || current_user).projects.order(:name)
60+
@windows_types = WindowsType.all.order(:name)
61+
@workshops = Workshop.all.order(:title)
62+
@users = User.all.order(:first_name, :last_name)
63+
end
64+
65+
# def remove_image
66+
# @story_idea = StoryIdea.find(params[:id])
67+
# @image = @story_idea.images.find(params[:image_id])
68+
# @image.purge
69+
#
70+
# respond_to do |format|
71+
# format.turbo_stream
72+
# format.html { redirect_to edit_story_path(@story_idea), notice: "Image removed." }
73+
# end
74+
# end
75+
76+
private
77+
78+
def set_story
79+
@story_idea = StoryIdea.find(params[:id])
80+
end
81+
82+
# Strong parameters
83+
def story_idea_params
84+
params.require(:story_idea).permit(
85+
:title, :body, :youtube_url,
86+
:permission_given, :publish_preferences, :promoted_to_story,
87+
:windows_type_id, :project_id, :workshop_id,
88+
:created_by_id, :updated_by_id,
89+
:main_image, images: []
90+
)
91+
end
92+
end

app/models/story_idea.rb

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
class StoryIdea < ApplicationRecord
2+
belongs_to :created_by, class_name: "User"
3+
belongs_to :updated_by, class_name: "User"
4+
5+
belongs_to :project
6+
belongs_to :windows_type
7+
belongs_to :workshop
8+
has_many :stories
9+
10+
validates :windows_type_id, presence: true
11+
validates :project_id, presence: true
12+
validates :workshop_id, presence: true
13+
validates :created_by_id, presence: true
14+
validates :updated_by_id, presence: true
15+
validates :body, presence: true
16+
validates :permission_given, presence: true
17+
validates :publish_preferences, presence: true
18+
19+
# Images
20+
ACCEPTED_CONTENT_TYPES = ["image/jpeg", "image/png" ].freeze
21+
has_one_attached :main_image
22+
has_many_attached :images
23+
validates :main_image, content_type: ACCEPTED_CONTENT_TYPES
24+
validates :images, content_type: ACCEPTED_CONTENT_TYPES
25+
26+
def name
27+
title
28+
end
29+
30+
def full_name
31+
"#{created_at.strftime("%Y-%m-%d")} #{author_credit}: #{title}"
32+
end
33+
34+
def author_credit
35+
case publish_preferences
36+
when "I would like my full name published with the story"
37+
created_by.full_name
38+
when "I would like only my first name published"
39+
created_by.first_name
40+
else # "I do not want my name published with my story"
41+
"Anonymous"
42+
end
43+
end
44+
45+
def organization_name
46+
project.name
47+
end
48+
49+
def organization_location
50+
project.location&.name || project.locality
51+
end
52+
53+
def organization_description
54+
"#{organization_name}, #{organization_location}"
55+
end
56+
end

app/views/shared/_form_image_field.html.erb

Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,70 @@
44
<% label ||= field_name.to_s.titleize %>
55
<% hint ||= nil %>
66
<% rounded ||= false %>
7+
<% multiple ||= false %>
8+
<% image ||= nil %>
9+
<% show_file_field = local_assigns.fetch(:show_file_field, true) %>
10+
<% show_existing = local_assigns.fetch(:show_existing, true) %>
11+
<% unique_id = "#{field_name}-#{SecureRandom.hex(4)}" %>
712

813
<%= f.label label, class: "block font-medium gap-1 text-gray-700 string required" %>
914
<% if hint %>
1015
<%= f.hint hint.html_safe, wrap_with: { tag: :p, class: "text-gray-500 text-sm" } %>
1116
<% end %>
12-
<% if resource.public_send(field_name).attached? %>
13-
<%= image_tag url_for(resource.public_send(field_name)),
14-
alt: "#{label} Image",
15-
id: "#{field_name}-preview",
16-
class: "w-32 h-32 #{"rounded" if rounded }-full object-cover
17-
border border-gray-300 shadow-sm img-#{"rounded" if rounded } #{field_name}" %>
18-
<% else %>
19-
<%= image_tag "missing.png",
20-
id: "#{field_name}-preview",
21-
class: "w-32 h-32 #{"rounded" if rounded }-full object-cover border border-dashed border-gray-300" %>
22-
<% end %>
23-
<div id="<%= field_name %>-filename" class="text-center text-sm text-gray-500">
24-
<%= resource.public_send(field_name).attachment&.filename.to_s %>
25-
</div>
2617

27-
<div class="relative w-36">
28-
<%= f.file_field field_name, id: "#{field_name}-input",
29-
class: "absolute inset-0 w-36 h-full opacity-0 cursor-pointer" %>
30-
<button type="button"
31-
class="w-full py-2 px-3 w-36 border border-gray-300 rounded-lg bg-white text-sm text-gray-700 hover:bg-gray-50">
32-
Choose file
33-
</button>
18+
<div class="flex flex-col items-center gap-2">
19+
<% if show_existing %>
20+
<% image_to_show =
21+
if image.present?
22+
image
23+
else
24+
attached = resource.public_send(field_name)
25+
if attached.is_a?(ActiveStorage::Attached::One)
26+
attached.attachment
27+
elsif attached.is_a?(ActiveStorage::Attached::Many)
28+
attached.attachments.first
29+
end
30+
end %>
31+
32+
<% if image_to_show&.blob.present? %>
33+
<%= image_tag url_for(image_to_show),
34+
alt: "#{field_name.to_s.humanize} Image",
35+
id: "#{unique_id}-preview",
36+
class: "w-32 h-32 #{'rounded-full' if rounded} object-cover border border-gray-300 shadow-sm" %>
37+
<% else %>
38+
<%= image_tag "missing.png",
39+
id: "#{unique_id}-preview",
40+
class: "w-32 h-32 #{'rounded-full' if rounded} object-cover border border-dashed border-gray-300" %>
41+
<% end %>
42+
43+
<div id="<%= unique_id %>-filename" class="text-center text-sm text-gray-500">
44+
<%= if image_to_show&.blob.present?
45+
image_to_show.filename.to_s
46+
else
47+
"No file selected"
48+
end %>
49+
</div>
50+
<% end %>
51+
52+
<% if show_file_field %>
53+
<div class="relative w-36">
54+
<%= f.file_field field_name,
55+
id: "#{unique_id}-input",
56+
multiple: multiple,
57+
class: "absolute inset-0 w-36 h-full opacity-0 cursor-pointer" %>
58+
<button type="button"
59+
class="w-full py-2 px-3 w-36 border border-gray-300 rounded-lg bg-white text-sm text-gray-700 hover:bg-gray-50">
60+
Choose file
61+
</button>
62+
</div>
63+
<% end %>
3464
</div>
65+
66+
<%#= link_to "🗑 Remove",
67+
remove_image_story_path(@story, image_id: image.id),
68+
data: { turbo_method: :delete, turbo_confirm: "Remove this image?" },
69+
class: "text-red-600 hover:text-red-800 text-sm" if image %>
70+
3571
<%#= f.input :remove_image, as: :boolean,
3672
label: "Remove file",
3773
wrapper_html: { class: "flex justify-center items-center mb-0" },
@@ -43,9 +79,9 @@
4379

4480
<script>
4581
document.addEventListener("turbo:load", function() {
46-
const input = document.getElementById("<%= field_name %>-input");
47-
const filenameDisplay = document.getElementById("<%= field_name %>-filename");
48-
const preview = document.getElementById("<%= field_name %>-preview");
82+
const input = document.getElementById("<%= unique_id %>-input");
83+
const filenameDisplay = document.getElementById("<%= unique_id %>-filename");
84+
const preview = document.getElementById("<%= unique_id %>-preview");
4985

5086
if (!input) return;
5187

app/views/shared/_navbar_new_button.html.erb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
new_workshop_variation_path,
2929
class:
3030
"block px-4 py-2 text-sm text-gray-700 focus:bg-gray-100 focus:outline-hidden" %>
31+
<%= link_to "New story",
32+
new_story_idea_path,
33+
class:
34+
"block px-4 py-2 text-sm text-gray-700 focus:bg-gray-100 focus:outline-hidden" %>
3135
</div>
3236
</div>
3337
</div>

0 commit comments

Comments
 (0)