Created
February 26, 2012 08:48
-
-
Save bokmann/1915372 to your computer and use it in GitHub Desktop.
Mel's solution
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Mel, | |
# | |
# Sorry, I read too much of a previous problem I had into your question and | |
# probably spun you off in the wrong direction. Jim's comment points you in | |
# the right direction, but its only going to get you so far because of a | |
# limitation in combining polymorphism and HasManyThrough. You will run into | |
# this error trying to do what you want to do: | |
# | |
# http://rubydoc.info/github/rails/rails/master/ActiveRecord/HasManyThroughAssociationPolymorphicSourceError | |
# | |
# | |
# but given you probably don't want the :through par anyway (that would ignore | |
# the :quantity), I think we can do exactly what you need. | |
# | |
# watch this code: | |
# lets create a small inventory: | |
apple = Item.create(:name => "Apple") | |
banana = Item.create(:name => "Banana") | |
strawberry = Item.create(:name => "Strawberry") | |
get_well_card = Item.create(:name => "Get Well Soon Card") | |
# lets build a fruit basket | |
fruit_basket = Kit.create(:name => "Fruit Basket") | |
# and put a bunch of fruit in it. | |
fruit_basket.kit_parts << KitPart.create(:part => strawberry, :quantity => 7) | |
fruit_basket.kit_parts << KitPart.create(:part => strawberry, :quantity => 7) | |
fruit_basket.kit_parts << KitPart.create(:part => banana, :quantity => 2) | |
# and we can see what kit parts it contains | |
fruit_basket.kit_parts | |
# => [#<KitPart id: 1, kit_id: 1, part_id: 3, part_type: "Item", quantity: 7>, #<KitPart id: 2, kit_id: 1, part_id: 2, part_type: "Item", quantity: 2>, #<KitPart id: 3, kit_id: 1, part_id: 1, part_type: "Item", quantity: 3>] | |
# and we have a convenience method that unrolls that for us. Note the implementation isn't a has many through because of the polymorphic error that causes. Rails doesn't know how to join 2 disparate tables: | |
fruit_basket.parts | |
# => [#<Item id: 3, name: "Strawberry">, #<Item id: 2, name: "Banana">, #<Item id: 1, name: "Apple">] | |
# lets create a get well package that includes a kit (our fruit basket) and an item (our get well card) | |
get_well_package = Kit.create(:name => "Get Well Basket") | |
get_well_package.kit_parts << KitPart.create(:part => fruit_basket, :quantity => 1) | |
get_well_package.kit_parts << KitPart.create(:part => get_well_card, :quantity => 1) | |
# and we can inspect it the same way as above: | |
get_well_package.kit_parts | |
# => [#<KitPart id: 4, kit_id: 2, part_id: 1, part_type: "Kit", quantity: 1>, #<KitPart id: 5, kit_id: 2, part_id: 4, part_type: "Item", quantity: 1>] | |
get_well_package.parts | |
# => [#<Kit id: 1, name: "Fruit Basket">, #<Item id: 4, name: "Get Well Soon Card">] | |
# Here is the code that makes this happen: | |
class CreateKits < ActiveRecord::Migration | |
def change | |
create_table :kits do |t| | |
t.string :name | |
end | |
end | |
end | |
class CreateItems < ActiveRecord::Migration | |
def change | |
create_table :items do |t| | |
t.string :name | |
end | |
end | |
end | |
class CreateKitParts < ActiveRecord::Migration | |
def change | |
create_table :kit_parts do |t| | |
t.integer :kit_id | |
t.integer :part_id | |
t.string :part_type | |
t.integer :quantity | |
end | |
end | |
end | |
class Item < ActiveRecord::Base | |
has_many :kit_parts, :as => :part | |
end | |
class Kit < ActiveRecord::Base | |
has_many :kit_parts | |
has_many :containing_kits, :class_name => "KitParts", :as => :part | |
# if you want to see an Exception that looks like the name was chosen | |
# by a Java developer, uncomment this association, comment out the | |
#'parts' method below, and try the sample code. | |
# | |
# has_many :parts, :through => :kit_parts | |
# | |
# rails can't go through a polymorphic relationship. | |
def parts | |
kit_parts.collect do |kp| | |
kp.part | |
end | |
end | |
end | |
class KitPart < ActiveRecord::Base | |
belongs_to :kit | |
belongs_to :part, :polymorphic => true | |
end |
@bokmann: thanks for your help with this problem. just a quick message to let you know i've found the code. i haven't studied it yet but, and especially after reading your comments on my gist, i think i can see where i went wrong: trying to maintain the traversal path from item to kit... i think...
Sorry to throw so many solutions at you - the last one best fits what
you're trying to do. ActiveResource has some dead-end paths when using
polymorphism or STI
Glad I could help.
…-db
On Mon, Feb 27, 2012 at 1:54 PM, Mel Riffe < ***@***.*** > wrote:
@bokmann: thanks for your help with this problem. just a quick message to
let you know i've found the code. i haven't studied it yet but, and
especially after reading your comments on my gist, i think i can see where
i went wrong: trying to maintain the traversal path from item to kit... i
think...
---
Reply to this email directly or view it on GitHub:
https://gist.github.com/1915372
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is why I love Ruby and RoR!
Although the problem might be complex to wrap your head around, the solution did not require any complex code...
Mel, I'm glad I saw your post to be able to look at this. I've struggled with this before and solved my situation with some fugly code.