I'm not sure what this question is even called, but is it possible to have a list in a model via:
array of word
equipment %w[foo bar kimi etc...]
equipcost %i[10 35 85 etc...]
or
enum
enum equipment: { foo: 10,
bar: 35,
kimi: 83,
etc...
}
Then save multiple in an array i.e.
t.string "equipment_list", default: [], array: true
{ equipment_list => ["foo", "bar"] } or { equipment_list => [10, 35] }
Then when the object is called via @object.equipment_list
, it references the the array of words
or enum
.
So in the view I say <%= @object.equipment_list %>
and have the foo and bar display. Or if I'm in the model I can have a method that adds the values to get a total cost:
def cost
e = self.equipment_list
e.value
e.inject(: )
end
Is there a ruby or rails way of doing this? The array of words
way seems wrong and the emun
way is only for a single value.
I found this but like they say it is an index not an actual value.
CodePudding user response:
Columns that are serialized as arrays are seldom a good way to go.
What you need is an equipments
table, with columns name
and cost
This table is associated with another model, I'll call it Store
just for an example:
# equipments.rb
class Equipment < ApplicationRecord
has_and_belongs_to_many :stores
end
# stores.rb
class Store < ApplicationRecord
has_and_belongs_to_many :equipments
def equipment_cost
equipments.pluck(:cost).sum
end
end
CodePudding user response:
Hardcoding that data into your application is just not a good idea unless you want to change the code every time the buisness logic demands trivial changes or you like being called up at 3 am. Using an array/JSON/HSTORE/Seialized Garbage Varchar column isn't actually a good approach either:
- No data normalization
- Bad type support (no Decimal type)
- No Assocations
- Violates First Normal Form (1NF)
Instead create a join table where you can store the relation between a store and equipment as well as any additional data that describes the relation between the two buisness entities:
class Equipment < ApplicationRecord
has_many :store_equipments
end
class Store
has_many :store_equipments
end
# rails g model store_equipment store:belongs_to equipment:belongs_to cost:decimal
class StoreEquipment < ApplicationRecord
belongs_to :store
belongs_to :equipment
end
Naming the table/model after the two things it joins is just a very lazy convention - use a more appropriate name that fits the buisness logic of what that thing actually represents when possible.
The exact implementation here will depend on your buisness logic and you'll have to consider stuff like how you want to handle quantities. If you wanted to get the sum of the cost of the equipment the naive implementation is:
# for a single record
store = Store.find(1)
equipment_cost = @store.store_equipments.sum(:cost)
# fetch it for a group of records in a single query
stores = Store.left_joins(:store_equipments)
.select(
Store.arel_table[Arel.star],
StoreEquipment.arel_table[:cost].sum.as('equipment_cost')
)
.group(:id)