1

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.

2 Answers 2

3

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
Sign up to request clarification or add additional context in comments.

7 Comments

So even if the equipment's table would only have 100 - 300 objects, creating a table to store them and using a joining table to map them would be the ideal/correct way to go?
definitely! In some apps I have worked on, there are tables with less than 12 rows! It's done that way b/c you get to use all of ActiveRecords features, querying, sorting, one-to-many associations... etc.
think of it this way... Ruby/Rails are object-oriented. We represent our business logic by objects. Equipments are objects, they have attributes: cost, purchase_date etc. ActiveRecord is for storing objects as "models".
I would generally agree with everything except the use of has_and_belongs_to_many here. It makes the assumption that you won't need to store anything except the two foreign key columns on the join table. Which is pretty silly as thats exactly where you would want to store stuff like the inventory, timestamps etc. While you can convert it into the much less useless has_many through: by later renaming the table, creating a model and adding a primary key I would just go that way to begin with. seancdavis.com/posts/…
It also would avoid the assumption that equipment costs the same for every store.
|
2

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/Serialized text column isn't actually a good approach either:

  • No data normalization
  • Bad type support (no Decimal type)
  • No Assocations
  • Violates First Normal Form (1NF)
  • Querying the data is both harder and less performant.

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
  has_many :stores, through: :store_equipments
end

class Store
  has_many :store_equipments
  has_many :equipments, through: :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)

1 Comment

Thanks for the info I did not even know what: No data normalization Bad type support (no Decimal type) Violates First Normal Form (1NF) Join table was the route I took because I do need to store additional info in the join tables.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.