nanenj icon

Ruby things

nanenj | PRO | 02/25/19 05:20:45 PM UTC | 0 ⭐ | 228 👁️ | Never ⏰ | []
text |

10.09 KB

|

None

|

0 👍

/

0 👎

class CreateOrders < ActiveRecord::Migration[5.2]
  def change
    create_table :orders do |t|
       t.timestamps
    end
  end
end
 class CreateItems < ActiveRecord::Migration[5.2]
  def change
    create_table :items do |t|
       t.timestamps
    end
  end
end
 class CreateAssemblies < ActiveRecord::Migration[5.2]
  def change
    create_table :assemblies do |t|
       t.timestamps
    end
  end
end
 class CreateOrderItems < ActiveRecord::Migration[5.2]
  def change
    create_table :order_items do |t|
      t.references :order, foreign_key: true
      t.references :item, foreign_key: true
      t.references :assembly, foreign_key: true
       t.timestamps
    end
  end
end
 class CreateAssemblyItems < ActiveRecord::Migration[5.2]
  def change
    create_table :assembly_items do |t|
      t.references :assembly, foreign_key: true
      t.references :item, foreign_key: true
       t.timestamps
    end
  end
end
 class Assembly < ApplicationRecord
  has_many :orders, through: :order_items
  has_many :assembly_items
  has_many :assemblies, through: :assembly_items
  has_many :items, through: :assembly_items
end
 class AssemblyItem < ApplicationRecord
  belongs_to :assembly
  belongs_to :item
end
 class Item < ApplicationRecord
  has_many :orders, through: :order_items
  has_many :assemblies, through: :assembly_items
end
 class Order < ApplicationRecord
  has_many :order_items
  has_many :assemblies, through: :order_items
  has_many :items, through: :assemblies
end
 class OrderItem < ApplicationRecord
  belongs_to :order
  belongs_to :item
  belongs_to :assembly
end
 Running via Spring preloader in process 23837
Loading development environment (Rails 5.2.2)
 irb(main):001:0> o = Order.first
  Order Load (0.3ms)  SELECT  "orders".* FROM "orders" ORDER BY "orders"."id" ASC LIMIT $1  [["LIMIT", 1]]
=> #<Order id: 1, created_at: "2019-02-25 17:26:00", updated_at: "2019-02-25 17:26:00">
irb(main):002:0> a = Assembly.first
  Assembly Load (0.3ms)  SELECT  "assemblies".* FROM "assemblies" ORDER BY "assemblies"."id" ASC LIMIT $1  [["LIMIT", 1]]
=> #<Assembly id: 1, created_at: "2019-02-25 17:26:35", updated_at: "2019-02-25 17:26:35">
irb(main):003:0> i = Item.first
  Item Load (0.4ms)  SELECT  "items".* FROM "items" ORDER BY "items"."id" ASC LIMIT $1  [["LIMIT", 1]]
=> #<Item id: 1, created_at: "2019-02-25 17:26:27", updated_at: "2019-02-25 17:26:27">
 irb(main):004:0> o.assemblies
  Assembly Load (0.7ms)  SELECT  "assemblies".* FROM "assemblies" INNER JOIN "order_items" ON "assemblies"."id" = "order_items"."assembly_id" WHERE "order_items"."order_id" = $1 LIMIT $2  [["order_id", 1], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Assembly id: 1, created_at: "2019-02-25 17:26:35", updated_at: "2019-02-25 17:26:35">]>
 irb(main):005:0> o.items
  Item Load (1.4ms)  SELECT  "items".* FROM "items" INNER JOIN "assembly_items" ON "items"."id" = "assembly_items"."item_id" INNER JOIN "assemblies" ON "assembly_items"."assembly_id" = "assemblies"."id" INNER JOIN "order_items" ON "assemblies"."id" = "order_items"."assembly_id" WHERE "order_items"."order_id" = $1 LIMIT $2  [["order_id", 1], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Item id: 1, created_at: "2019-02-25 17:26:27", updated_at: "2019-02-25 17:26:27">]>
 irb(main):006:0> a.orders
  Order Load (0.3ms)  SELECT  "orders".* FROM "orders" INNER JOIN "order_items" ON "orders"."id" = "order_items"."order_id" WHERE "order_items"."assembly_id" = $1 LIMIT $2  [["assembly_id", 1], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Order id: 1, created_at: "2019-02-25 17:26:00", updated_at: "2019-02-25 17:26:00">]>
 irb(main):007:0> a.assemblies
  Assembly Load (0.3ms)  SELECT  "assemblies".* FROM "assemblies" INNER JOIN "assembly_items" ON "assemblies"."id" = "assembly_items"."assembly_id" WHERE "assembly_items"."assembly_id" = $1 LIMIT $2  [["assembly_id", 1], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Assembly id: 1, created_at: "2019-02-25 17:26:35", updated_at: "2019-02-25 17:26:35">]>
 irb(main):008:0> a.items
  Item Load (0.4ms)  SELECT  "items".* FROM "items" INNER JOIN "assembly_items" ON "items"."id" = "assembly_items"."item_id" WHERE "assembly_items"."assembly_id" = $1 LIMIT $2  [["assembly_id", 1], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Item id: 1, created_at: "2019-02-25 17:26:27", updated_at: "2019-02-25 17:26:27">]>
 irb(main):009:0> i.orders
  Order Load (0.4ms)  SELECT  "orders".* FROM "orders" INNER JOIN "order_items" ON "orders"."id" = "order_items"."order_id" WHERE "order_items"."item_id" = $1 LIMIT $2  [["item_id", 1], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Order id: 1, created_at: "2019-02-25 17:26:00", updated_at: "2019-02-25 17:26:00">]>
 irb(main):010:0> i.assemblies
  Assembly Load (0.4ms)  SELECT  "assemblies".* FROM "assemblies" INNER JOIN "assembly_items" ON "assemblies"."id" = "assembly_items"."assembly_id" WHERE "assembly_items"."item_id" = $1 LIMIT $2  [["item_id", 1], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Assembly id: 1, created_at: "2019-02-25 17:26:35", updated_at: "2019-02-25 17:26:35">]>
irb(main):011:0>
 Notice that all of these relations (presumably) work and operate as expeted.
 However, when we try to use them in the way you described.
 irb(main):011:0> o.items
  Item Load (0.9ms)  SELECT  "items".* FROM "items" INNER JOIN "assembly_items" ON "items"."id" = "assembly_items"."item_id" INNER JOIN "assemblies" ON "assembly_items"."assembly_id" = "assemblies"."id" INNER JOIN "order_items" ON "assemblies"."id" = "order_items"."assembly_id" WHERE "order_items"."order_id" = $1 LIMIT $2  [["order_id", 1], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Item id: 1, created_at: "2019-02-25 17:26:27", updated_at: "2019-02-25 17:26:27">]>
irb(main):012:0> assemblies = o.assemblies
  Assembly Load (0.4ms)  SELECT  "assemblies".* FROM "assemblies" INNER JOIN "order_items" ON "assemblies"."id" = "order_items"."assembly_id" WHERE "order_items"."order_id" = $1 LIMIT $2  [["order_id", 1], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Assembly id: 1, created_at: "2019-02-25 17:26:35", updated_at: "2019-02-25 17:26:35">]>
irb(main):013:0> assemblies.items
Traceback (most recent call last):
        1: from (irb):13
  Assembly Load (0.6ms)  SELECT  "assemblies".* FROM "assemblies" INNER JOIN "order_items" ON "assemblies"."id" = "order_items"."assembly_id" WHERE "order_items"."order_id" = $1 LIMIT $2  [["order_id", 1], ["LIMIT", 11]]
NoMethodError (undefined method `items' for #<Assembly::ActiveRecord_Associations_CollectionProxy:0x00007f921ec785a0>)
irb(main):014:0>
 We get that error because assemblies isn't actually a single thing, so we can't call items on it directly.
 irb(main):017:0> assemblies.map { |assembly|
irb(main):018:1* assembly.items
irb(main):019:1> }
  Item Load (0.5ms)  SELECT  "items".* FROM "items" INNER JOIN "assembly_items" ON "items"."id" = "assembly_items"."item_id" WHERE "assembly_items"."assembly_id" = $1 LIMIT $2  [["assembly_id", 1], ["LIMIT", 11]]
=> [#<ActiveRecord::Associations::CollectionProxy [#<Item id: 1, created_at: "2019-02-25 17:26:27", updated_at: "2019-02-25 17:26:27">]>]
irb(main):020:0>
 In that way, we can iterate over each of the assemblies and return a value.  Much like your later comment suggest where it's assemblies.each.   While my models do not have a name, we can pretend we wanted a specific data structure.
 irb(main):017:0> assemblies.map { |assembly|
irb(main):018:1* assembly.items
irb(main):019:1> }
  Item Load (0.5ms)  SELECT  "items".* FROM "items" INNER JOIN "assembly_items" ON "items"."id" = "assembly_items"."item_id" WHERE "assembly_items"."assembly_id" = $1 LIMIT $2  [["assembly_id", 1], ["LIMIT", 11]]
=> [#<ActiveRecord::Associations::CollectionProxy [#<Item id: 1, created_at: "2019-02-25 17:26:27", updated_at: "2019-02-25 17:26:27">]>]
irb(main):020:0>
 So, you could alternatively, define a method that does the above on order, however, while I may not have the exact API you desired, if I were to create another assembly, item, order_item, and assembly_item, I can achieve...
 irb(main):058:0> o.items
  Item Load (0.8ms)  SELECT  "items".* FROM "items" INNER JOIN "assembly_items" ON "items"."id" = "assembly_items"."item_id" INNER JOIN "assemblies" ON "assembly_items"."assembly_id" = "assemblies"."id" INNER JOIN "order_items" ON "assemblies"."id" = "order_items"."assembly_id" WHERE "order_items"."order_id" = $1 LIMIT $2  [["order_id", 1], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Item id: 1, created_at: "2019-02-25 17:26:27", updated_at: "2019-02-25 17:26:27">, #<Item id: 2, created_at: "2019-02-25 18:03:06", updated_at: "2019-02-25 18:03:06">]>
irb(main):059:0>
 However, you can also achieve what you're after by using a scope.
 If you add the scope:
  scope :items, -> { AssemblyItem.where(assembly_id: self.ids).map { |ai|
    ai.item
  }}
 to your Assembly model, you should be able to do the following...
 irb(main):031:0> o = Order.first
  Order Load (0.3ms)  SELECT  "orders".* FROM "orders" ORDER BY "orders"."id" ASC LIMIT $1  [["LIMIT", 1]]
=> #<Order id: 1, created_at: "2019-02-25 17:26:00", updated_at: "2019-02-25 17:26:00">
irb(main):032:0> o.assemblies.items
   (0.3ms)  SELECT "assemblies"."id" FROM "assemblies" INNER JOIN "order_items" ON "assemblies"."id" = "order_items"."assembly_id" WHERE "order_items"."order_id" = $1  [["order_id", 1]]
  AssemblyItem Load (0.3ms)  SELECT "assembly_items".* FROM "assembly_items" WHERE "assembly_items"."assembly_id" IN ($1, $2)  [["assembly_id", 1], ["assembly_id", 2]]
  Item Load (3.3ms)  SELECT  "items".* FROM "items" WHERE "items"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
  Item Load (0.3ms)  SELECT  "items".* FROM "items" WHERE "items"."id" = $1 LIMIT $2  [["id", 2], ["LIMIT", 1]]
=> [#<Item id: 1, created_at: "2019-02-25 17:26:27", updated_at: "2019-02-25 17:26:27">, #<Item id: 2, created_at: "2019-02-25 18:03:06", updated_at: "2019-02-25 18:03:06">]
irb(main):033:0>

Comments