Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- 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>
Add Comment
Please, Sign In to add comment