diff --git a/app/controllers/slots_controller.rb b/app/controllers/slots_controller.rb new file mode 100644 index 000000000..36517beee --- /dev/null +++ b/app/controllers/slots_controller.rb @@ -0,0 +1,19 @@ +class SlotsController < ApplicationController + expose :slot, scope: -> { policy_scope(current_room.slots) } + + def new + authorize(slot) + end + + def create + if authorize(slot).save + redirect_to(slot.slottable.location) + else + render :new, status: :unprocessable_entity + end + end + + def slot_params + params.require(:slot).permit([:slottable_type]) + end +end diff --git a/app/lib/space_routes.rb b/app/lib/space_routes.rb index 6f3891ee4..2b96f8478 100644 --- a/app/lib/space_routes.rb +++ b/app/lib/space_routes.rb @@ -8,6 +8,7 @@ def self.append_routes(router) router.resources :rooms, only: %i[show edit update new create destroy] do Furniture.append_routes(router) router.resources :furnitures, only: %i[create edit update destroy] + router.resources :slots, only: %i[new create] router.resource :hero_image, controller: "room/hero_images" end diff --git a/app/models/room.rb b/app/models/room.rb index 4794a282a..596893070 100644 --- a/app/models/room.rb +++ b/app/models/room.rb @@ -30,6 +30,8 @@ class Room < ApplicationRecord has_many :gizmos, dependent: :destroy, inverse_of: :room, class_name: :Furniture accepts_nested_attributes_for :gizmos + has_many :slots, dependent: :destroy, inverse_of: :section + DESCRIPTION_MAX_LENGTH = 300 validates :description, length: {maximum: DESCRIPTION_MAX_LENGTH, allow_blank: true} diff --git a/app/models/slot.rb b/app/models/slot.rb index 6cf8228ba..30095d45f 100644 --- a/app/models/slot.rb +++ b/app/models/slot.rb @@ -1,6 +1,8 @@ class Slot < ApplicationRecord - belongs_to :section, class_name: "Room" - belongs_to :slottable, polymorphic: true + belongs_to :section, class_name: "Room", inverse_of: :slots + has_one :space, through: :section + + belongs_to :slottable, polymorphic: true, inverse_of: :slot include RankedModel ranks :slot_order, with_same: [:section_id] diff --git a/app/policies/slot_policy.rb b/app/policies/slot_policy.rb new file mode 100644 index 000000000..80da6fd56 --- /dev/null +++ b/app/policies/slot_policy.rb @@ -0,0 +1,10 @@ +class SlotPolicy < ApplicationPolicy + alias_method :slot, :object + + def create? + current_person.operator? || current_person.member_of?(slot.space) + end + + class Scope < ApplicationScope + end +end diff --git a/app/views/rooms/edit.html.erb b/app/views/rooms/edit.html.erb index fab30b491..b87a0ce64 100644 --- a/app/views/rooms/edit.html.erb +++ b/app/views/rooms/edit.html.erb @@ -11,6 +11,19 @@ <%= render "rooms/hero_image/form", room: room %> <% end %> <%- end %> + +<%- if current_person.operator? || Rails.env.test? %> + <%= render CardComponent.new do |card| %> + <%- card.with_header do %> +

Gizmos (but lighter)

+ <%- end %> + + <%- card.with_footer(variant: :action_bar) do%> + <%= link_to "Add a Slottable", room.location(:new, child: :slot), + class: "button w-full" %> + <%- end %> + <%- end %> +<%- end %>
<%= render CardComponent.new do %>

Gizmos

diff --git a/app/views/slots/new.html.erb b/app/views/slots/new.html.erb new file mode 100644 index 000000000..ff297fb68 --- /dev/null +++ b/app/views/slots/new.html.erb @@ -0,0 +1,5 @@ +<%= form_with(model: [slot.space, slot.section, slot]) do |slot_form| %> + <%= slot_form.label(:slottable_type) %> + <%= slot_form.select(:slottable_type, [:MarkdownTextBlock]) %> + <%= slot_form.submit %> +<%- end %> diff --git a/spec/models/room_spec.rb b/spec/models/room_spec.rb index 1db962ace..38a1746fe 100644 --- a/spec/models/room_spec.rb +++ b/spec/models/room_spec.rb @@ -4,6 +4,8 @@ let(:space) { Space.new } it { is_expected.to have_many(:gizmos).inverse_of(:room).dependent(:destroy) } + it { is_expected.to have_many(:slots).inverse_of(:section).dependent(:destroy) } + it { is_expected.to belong_to(:space).inverse_of(:rooms) } describe "#description" do diff --git a/spec/models/slot_spec.rb b/spec/models/slot_spec.rb index 3eae57e7f..cd0b5fd8c 100644 --- a/spec/models/slot_spec.rb +++ b/spec/models/slot_spec.rb @@ -1,6 +1,6 @@ require "rails_helper" RSpec.describe Slot do - it { is_expected.to belong_to(:section).class_name(:Room) } - it { is_expected.to belong_to(:slottable) } + it { is_expected.to belong_to(:section).class_name(:Room).inverse_of(:slots) } + it { is_expected.to belong_to(:slottable).inverse_of(:slot) } end diff --git a/spec/system/slots_system_spec.rb b/spec/system/slots_system_spec.rb index 5ea044d2c..19ceac81c 100644 --- a/spec/system/slots_system_spec.rb +++ b/spec/system/slots_system_spec.rb @@ -8,14 +8,14 @@ sign_in(space.members.first, space) visit(polymorphic_path(section.location(:edit))) - click_link("Add a Slottable") + click_link("Add Text Block") + expect(page).to have_current_path(polymorphic_path(section.location(:new, child: :text_block))) - select("Text Block", from: "Type") - - click_button("Create Slottable") + fill_in_rich_text_area("Body", with: "Prepare yourself for AMAZING") + click_button("Create") expect(section.slots.count).to eq(1) - expect(section.slots.slottable).to be_a(TextBlock) - expect(page).to have_current_path(polymorphic_path(section.slots.slottable)) + expect(section.slots.first.slottable).to be_a(TextBlock) + expect(sections.slots.first.slottable.body).to eq("Prepare yourself for AMAZING") end end