I have a collection of objects. What I would like to do is iterate over the entire collection, but show each object on a page/view by itself, and allow the user to interact with each object individually. Ideally, I would prefer not to use a multi-part form if I can avoid it, for reasons I spell out at the end of my question.
I am trying to implement screens like the images below.
Basically the user of the app, will go to a location to do a reconciliation of inventory (of each product) in that location. That's what the screens are showing. For each product, they have to update the inventory.
The summary & requirements are as follows:
location has_many inventory_items
.user
begins a reconciliation
whenever they want to do an inventory check.reconciliation habtm inventory_items
&& belongs_to :location
.inventory_item habtm reconciliations
&& belongs_to :location
.inventory_items
there are.inventory_items
.inventory_items
into different groups if the number becomes unwieldy....similar to a pagination approach.So my models look like this:
Reconciliation
# == Schema Information
#
# Table name: reconciliations
#
# id :integer not null, primary key
# location_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
class Reconciliation < ApplicationRecord
belongs_to :location
has_and_belongs_to_many :inventory_items
end
Location
# == Schema Information
#
# Table name: locations
#
# id :integer not null, primary key
# name :string
# created_at :datetime not null
# updated_at :datetime not null
#
class Location < ApplicationRecord
has_and_belongs_to_many :products
has_many :inventory_items, inverse_of: :location
accepts_nested_attributes_for :inventory_items
has_many :reconciliations
end
Inventory Item
# == Schema Information
#
# Table name: inventory_items
#
# id :integer not null, primary key
# product_id :integer
# location_id :integer
# quantity_left :integer
# quantity_delivered :integer
# quantity_on_hand :integer
# date_of_last_delivery :datetime
# created_at :datetime not null
# updated_at :datetime not null
#
class InventoryItem < ApplicationRecord
belongs_to :product
belongs_to :location, inverse_of: :inventory_items
has_and_belongs_to_many :reconciliations
end
Here is my inventory_items_reconciliations Join Table
:
create_table "inventory_items_reconciliations", id: false, force: :cascade do |t|
t.bigint "inventory_item_id", null: false
t.bigint "reconciliation_id", null: false
t.index ["inventory_item_id", "reconciliation_id"], name: "index_inventory_item_id_reconciliation_id_join"
t.index ["reconciliation_id", "inventory_item_id"], name: "index_reconciliation_id_inventory_item_id_join"
end
My routes.rb
:
resources :locations, shallow: true do
resources :inventory_items
resources :reconciliations
end
My ReconciliationsController#New
:
def new
@location = Location.find(params[:location_id])
@reconciliation = @location.reconciliations.new
@inventory_items = @location.inventory_items
@num_of_inventory_items = @inventory_items.coun
end
My app/views/reconciliations/new.html.erb
:
<% @inventory_items.each do |inventory_item| %>
<%= render 'form', reconciliation: @reconciliation, inventory_item: inventory_item %>
<% end %>
My app/views/reconciliations/_form.html.erb
:
<%= simple_form_for @reconciliation, url: :location_reconciliations do |f| %>
<%= f.error_notification %>
<strong>Name</strong>: <%= inventory_item.product.name %> <br />
<strong>Quantity Left:</strong> <%= inventory_item.quantity_left %> <br />
<strong>Quantity Delivered:</strong> <%= inventory_item.quantity_delivered %> <br />
<div class="form-actions">
<%= f.button :submit, "Update", class: "btn btn-primary" %>
</div>
<% end %>
What this does is just displays all of the location.inventory_items
on that reconciliation page, when all I want is for 1 to be displayed.
So, what I would like to do is this:
inventory_items
in the location that the user has chosen.inventory_item
as reconciled
even if the user didn't update the quantity (i.e. say there have been no sold since it was delivered).inventory_items
in this collection are iterated over, then save the reconciliation
record to the database that accurately reflects the quantity information for each inventory_item
within this reconiliation cycle
.I looked at the Wicked Gem, but it seems that I need to be able to statically declare the number of steps in advance. As you can see above, if each inventory_item
in my collection is a step, there needs to be a dynamic number of steps.
I also came across similar constraints with other multi-step wizard approaches.
How do I achieve what I am trying to do?
What is a reconciliation?
i) “A procedure for confirming that the balance in a chequebook matches the corresponding bank statement. This is normally done by preparing a bank reconciliation statement.
ii) A procedure for confirming the reliability of a company’s accounting records by regularly comparing [balances of transactions]. An account reconciliation may be prepared on a daily, monthly, or annual basis.”
user
has_many items
warehouse
has_many accounts
accounts
has_many items
warehouse
has_many items
, throught: :accounts
item
belongs_to warehouse
class Product
has_many :items
accepts_nested_attributes_for :items
end
class Item
belongs_to :product
end
class Account
has_many :products
has_many :warehouses, through: :products
end
class Warehouse
has_many :products
has_many :accounts, through: :products
end
Your routes.rb
resources :warehouses do
resources :products
resources :accounts
end
resources :accounts do
resources :products
resources :warehouses
end
resources :products do
resources :items
end
The account
model will have a reconciled
field.
This is your form. It is displaying a Product
.
form_for @product do |f|
<!-- your fields: account_id and number of items-->
f.fields_for :items do |item|
<!-- your item -->
end
f.submit
end
ProductsController#update
def update
warehouse = Warehouse.find(params[:warehouse_id])
@product = warehouse.products.first
# needs to be refactored
if @product.update && @product.is_the_last_one
redirect_to :your_choosen_root
elsif @product.update
redirect_to edit_product_path(@product.next)
else
render :edit
end
end
Once all inventory_items in this collection are iterated over, then save the reconciliation record to the database that accurately reflects the quantity information for each inventory_item within this reconiliation cycle.
I'll think about it tomorrow (it's 22:55) :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With