Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 46 additions & 9 deletions app/admin/categories.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
id_column
column :name
column('Disabled') { |item| status_tag item.is_disabled, label: item.is_disabled? ? 'True' : 'False' }
column :items_count
column :created_at
column :updated_at
actions defaults: false do |category|
Expand All @@ -34,6 +35,27 @@
f.input :description
end
f.actions

if edit_action?
panel "Items" do
div do
link_to 'Add Item', new_admin_item_path(category_id: resource.id), class: 'button'
end

items = resource.items

if items.any?
table_for items do
column 'Item name' do |item|
link_to item.name, edit_admin_item_path(item)
end
column 'Item description', :description
end
else
"Items not found"
end
end
end
end

show do
Expand All @@ -44,6 +66,25 @@
row :created_at
row :updated_at
end

panel "Items" do
div do
link_to 'Add Item', new_admin_item_path(category_id: resource.id), class: 'button'
end

items = resource.items

if items.any?
table_for items do
column 'Item name' do |item|
link_to item.name, admin_item_path(item)
end
column 'Item description', :description
end
else
"Items not found"
end
end
end

action_item :toggle, only: :show do
Expand All @@ -64,21 +105,17 @@
resource.toggle(:is_disabled)

if resource.save
# rubocop:disable Rails/SkipsModelValidations
resource.items.update_all(is_disabled: true) if resource.is_disabled?
# rubocop:enable Rails/SkipsModelValidations

redirect_to admin_categories_path, notice: "Category was successfully #{resource.is_disabled? ? 'disabled' : 'enabled'}."
else
redirect_to admin_categories_path, alert: resource.errors.messages_for(:name)
end
end

controller do
def create
@category = Category.new(permitted_params[:category])

if @category.save
redirect_to admin_categories_path, notice: 'Category was successfully created.'
else
render :new
end
end
helper ActiveAdmin::ActionCheckHelper
end
end
40 changes: 32 additions & 8 deletions app/admin/items.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
filter :is_disabled, label: "Disabled"

index do
selectable_column
id_column
column :name
column :category, sortable: :category_id
Expand Down Expand Up @@ -46,7 +47,7 @@
f.input :category_id, as: :select,
collection: Category.pluck(:name, :id),
include_blank: "No Category",
selected: f.object.category_id.presence || meta_data["category_id"]
selected: f.object.category_id.presence || meta_data["category_id"] || params[:category_id]
end

div class: "add-param-link-wrapper" do
Expand Down Expand Up @@ -81,8 +82,8 @@
end
end

tmp_fixed = session_service.get(:fixed) || {}
tmp_open = session_service.get(:open) || []
tmp_fixed = session_service.get(:fixed) || {}
tmp_open = session_service.get(:open) || []
tmp_select = session_service.get(:select) || {}

panel "Pricing Parameters" do
Expand Down Expand Up @@ -140,6 +141,19 @@
end
end

batch_action :assign_to_category, form: -> { { category: Category.pluck(:name, :id) } } do |ids, inputs|
category = Category.find_by(id: inputs[:category])

if category
# rubocop:disable Rails/SkipsModelValidations
Item.where(id: ids).update_all(category_id: category.id)
# rubocop:enable Rails/SkipsModelValidations
redirect_to admin_items_path, notice: "Category was successfully assigned."
else
redirect_back fallback_location: admin_items_path, alert: "Category not found."
end
end

controller do
helper_method :session_service

Expand All @@ -149,6 +163,7 @@ def create

if @item.save
session_service.delete

redirect_to admin_item_path(@item), notice: "Item was successfully created."
else
flash.now[:error] = "Failed to create item: #{@item.errors.full_messages.to_sentence}"
Expand Down Expand Up @@ -181,7 +196,12 @@ def update

if @item.update(permitted_params[:item].except(:formula_parameters))
session_service.delete
redirect_to admin_item_path(@item), notice: "Item was successfully updated."

if @item.category.present?
redirect_to edit_admin_category_path(@item.category), notice: "Item was successfully updated."
else
redirect_to admin_item_path(@item), notice: "Item was successfully updated."
end
else
flash[:error] = "Failed to update item: #{@item.errors.full_messages.to_sentence}"
render :edit
Expand Down Expand Up @@ -212,7 +232,11 @@ def session_service
end

action_item :back, only: :show do
link_to "Back to Items", admin_items_path
if resource.category.present?
link_to "Back to Category", admin_category_path(resource.category)
else
link_to "Back to Items", admin_items_path
end
end

member_action :toggle, method: :put do
Expand All @@ -229,8 +253,8 @@ def session_service

param_type = params[:parameter_type]
param_name = case param_type
when "Fixed" then params[:fixed_parameter_name].to_s.strip
when "Open" then params[:open_parameter_name].to_s.strip
when "Fixed" then params[:fixed_parameter_name].to_s.strip
when "Open" then params[:open_parameter_name].to_s.strip
when "Select" then params[:select_parameter_name].to_s.strip
end

Expand Down Expand Up @@ -269,7 +293,7 @@ def session_service
valid_options = false
(params[:select_options] || []).each do |pair|
desc = pair["description"].to_s.strip
val = pair["value"].to_s.strip
val = pair["value"].to_s.strip
next if desc.blank? || val.blank?

sub_hash[desc] = val
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module ActiveAdmin
module ResourceHelper
module ActionCheckHelper
def edit_action?
params[:action] == 'edit'
end
Expand Down
2 changes: 2 additions & 0 deletions app/models/category.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
class Category < ApplicationRecord
has_many :items, dependent: :nullify

ASCII_CHARACTERS = /\A[[:ascii:]]*\z/

has_many :items, dependent: :nullify
Expand Down
4 changes: 3 additions & 1 deletion app/models/item.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class Item < ApplicationRecord
belongs_to :category, optional: true
belongs_to :category, optional: true, counter_cache: true

validates :name, presence: true
validates :name, uniqueness: { scope: :category_id, message: "Item name must be unique within category" }
Expand All @@ -9,6 +9,8 @@ class Item < ApplicationRecord
validates :calculation_formula, presence: true, if: :requires_calculation_formula?
validate :calculation_formula_must_be_valid, if: :requires_calculation_formula?

scope :without_category, -> { where(category_id: nil) }

def self.ransackable_attributes(_auth_object = nil)
%w[category_id created_at id is_disabled name updated_at]
end
Expand Down
5 changes: 5 additions & 0 deletions db/migrate/20250501143252_add_items_count_to_categories.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddItemsCountToCategories < ActiveRecord::Migration[8.0]
def change
add_column :categories, :items_count, :integer, default: 0, null: false
end
end
3 changes: 2 additions & 1 deletion db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions spec/requests/admin/categories_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@
end

describe 'POST /admin/categories' do
it 'checks redirect to the categories page and successfully creates a category' do
it 'checks redirect to the category page and successfully creates a category' do
post admin_categories_path, params: { category: { name: 'Category', description: 'Description' } }

expect(response).to redirect_to(admin_categories_path)
expect(response).to redirect_to(admin_category_path(Category.last))

follow_redirect!

Expand Down
83 changes: 73 additions & 10 deletions spec/requests/admin/items_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,45 @@
}
end

let(:valid_params_without_category) do
{
item: {
name: 'Test Item',
description: 'A test item'
}
}
end

let(:invalid_params) { { item: { name: '' } } }

it 'creates a new item and redirects' do
expect do
post '/admin/items', params: valid_params
end.to change(Item, :count).by(1)
context 'when a category is' do
it 'not selected and redirects to the item page' do
expect do
post admin_items_path, params: valid_params_without_category
end.to change(Item, :count).by(1)

expect(response).to redirect_to(%r{/admin/items/\d+})
follow_redirect!
expect(response.body).to include('Test Item')
expect(response).to redirect_to(admin_item_path(Item.last))

follow_redirect!

expect(response).to have_http_status(:ok)
expect(response.body).to include('Test Item')
expect(response.body).to include('Item was successfully created.')
end

it 'selected and redirects to the item page' do
expect do
post admin_items_path(category_id: category.id), params: valid_params
end.to change(Item, :count).by(1)

expect(response).to redirect_to(admin_item_path(Item.last))

follow_redirect!

expect(response).to have_http_status(:ok)
expect(response.body).to include('Test Item')
expect(response.body).to include('Item was successfully created.')
end
end

context 'with session parameters' do
Expand Down Expand Up @@ -114,7 +143,7 @@
expect(item.is_fixed).to be true
expect(item.is_open).to be true
expect(item.is_selectable_options).to be true
expect(response).to redirect_to(%r{/admin/items/\d+})
expect(response).to redirect_to(admin_item_path(item))
end

it 'does not create an item with invalid params' do
Expand All @@ -137,16 +166,50 @@
}
}
end

let(:valid_params_without_category) do
{
item: {
name: 'Updated Item',
description: 'Updated description',
category_id: nil
}
}
end
let(:invalid_params) { { item: { name: '' } } }

context 'when category is' do
it 'selected and redirects to the edit category page' do
put admin_item_path(item), params: valid_params

expect(response).to redirect_to(edit_admin_category_path(category))

follow_redirect!

expect(response).to have_http_status(:ok)
expect(response.body).to include('Updated Item')
expect(response.body).to include("Item was successfully updated.")
end

it 'not selected and redirects to the item page' do
put admin_item_path(item), params: valid_params_without_category

expect(response).to redirect_to(admin_item_path(item))

follow_redirect!

expect(response).to have_http_status(:ok)
expect(response.body).to include('Updated Item')
expect(response.body).to include("Item was successfully updated.")
end
end

it 'updates the item and redirects' do
put "/admin/items/#{item.id}", params: valid_params
item.reload

expect(item.name).to eq('Updated Item')
expect(item.description).to eq('Updated description')
expect(response).to redirect_to("/admin/items/#{item.id}")
expect(response).to redirect_to(edit_admin_category_path(item.category))
follow_redirect!
expect(response.body).to include('Updated Item')
end
Expand Down