2012-01-08 11 views
3

私は2つのテーブルを持っています。アイテム、およびベンダー。アイテムはベンダーによって販売されています。したがって、アイテムbelongs_to:ベンダーおよびベンダーhas_many:アイテム。それはうまく動作します。Rails 3.1高度なHas_manyとbelongs_toモデルの結合

ただし、商品を販売するベンダーによって商品が製造されるとは限りません。だから私は "manufacturer_id"と呼ばれる私のアイテムテーブルに新しい列を持っています。ベンダーを同じように複製するManufacturerという新しいモデルを生成するのではなく、has_manyとbelongs_toの複合体を作成して製造元を定義しようとしました。

こちらを参照してください:作成したコマンドで期待どおりの項目テーブルにMANUFACTURER_IDを移植

class Item < ActiveRecord::Base 
    belongs_to :vendor 
    belongs_to :manufacturer, :class_name => "Vendor", :foreign_key => "manufacturer_id" 
end 

class Vendor < ActiveRecord::Base 
    has_many :items 
    has_many :manufactured_items, :class_name => "Item", :foreign_key => "manufacturer_id" 
end 

作品:

Item.create(:manufacturer => Vendor.find_by_abbrev("INV")) 

そして、私も運転

item.manufacturer 
としてメーカーを得ることができます

戻り値:

<Vendor:0x007ff06684e398> 

もつとも:

item.manufacturer.name 

ハードexeptionで完全に失敗し、私はエラーを取得:

undefined method `name' for nil:NilClass 

debug item.manufacturer 

を実行すると、

--- !ruby/object:Vendor 
attributes: 
    id: 181 
    name: Invitrogen 
    website: http://www.invitrogen.com/ 
    created_at: 2012-01-08 01:39:07.486375000Z 
    updated_at: 2012-01-08 01:39:07.486375000Z 
    abbrev: INV 
0123を与えます

したがって、item.manufacturer.nameは、上記のベンダーオブジェクトの名前(Vendor:0x007ff06684e398)を返す必要があります。

私はここで間違っていますか?

vendor.manufactured_items 

をそのベンダーのMANUFACTURER_IDを持つすべてのアイテムを取得するために:私はこの作業を取得後

また、私は同様に呼び出すことができるようにしたいと思います。あまりにも簡単な方法がありますか?

私の土壇場の努力を行うに持つ伴うことがあります。

メーカー= Vendor.new(item.manufacturer)

しかし、それは完全に間違っているようだ、とここではレールのドキュメントに反する: http://guides.rubyonrails.org/association_basics.html#self-joins

助けてください!

答えて

3

私は実際にあなたのデモ用Rails 3.1プロジェクトとposted it on GitHubをビルドしました。 READMEファイルにコンソール出力を含めて、item.seller.nameitem.manufacturer.nameなどの通話と、特定のベンダーの最初に販売されたアイテムの製造元の名前を取得できるような往復の通話(vendor.sold_items.first.manufacturer.name)を証明しました、 例えば。

私は、あなたが指摘したように、すべての目的と目的のためにvendormanufacturerが同一であると考えています。そのために私はそれらを単にVendorクラスに組み込み、それが望むと思うように動作するように外部キーの関係を設定しました。

特に、READMEファイルに注意する必要があります。このファイルには、コンソールセッションの出力が表示されています。また、2つのモデルクラスとそれらの関連付けがどのように定義されているか、偽のデータベースデータを設定する方法については、spec/factories.rbファイルを参照してください。

あなたの質問を今朝読んで、私はあなたが間違っていたかどうかは分かりませんが、恐らくあなたの団体のどこかの微妙な誤りにそれを打ち消すことができます。おそらくあなたの場合は、が本当にに近いですが、それほどではありません。 :D

は、ここでは、コードからいくつかのsnipetsです:

アプリ/モデル/ item.rb

class Item < ActiveRecord::Base 
    belongs_to :seller, :class_name => "Vendor" 
    belongs_to :manufacturer, :class_name => "Vendor" 
end 

アプリ/モデル/ vendor.rb

class Vendor < ActiveRecord::Base 
    has_many :sold_items, :class_name => "Item", :foreign_key => :seller_id 
    has_many :manufactured_items, :class_name => "Item", :foreign_key => :manufacturer_id 
end 

spec/factories.rb

私の問題は解決しませんでした
require 'populator' 
require 'faker' 

FactoryGirl.define do 

    factory :vendor do |v| 
    v.name   {Populator.words(1..3)} 
    v.website   {Faker::Internet.domain_name} 
    v.abbr   {(["ABC", "DEF", "GHI", "JKL", "MNO", "PQR", "STU", "VWX", "YZ1"])[rand(9)]} 
    end 

    factory :item do |i| 
    i.association :seller, :factory => :vendor 
    i.association :manufacturer, :factory => :vendor 
    i.name {Populator.words(3..5)} 
    end 

end 

のlib /タスク/ populator.rake

namespace :db do 
    desc "Erase database" 
    task :erase => :environment do 
    puts "Erasing..." 

    [Vendor, Item].each(&:delete_all) 
    end 

    desc "Erase and fill database" 
    task :populate => [:environment, :erase] do 
    require 'populator' 
    require 'faker' 

    puts "Populating: enjoy this random pattern generator while you wait..." 

    50.times{Factory.create(:vendor)} 
    Vendor.all.each do |v| 
     # This line actually has a bug in it that makes all `seller_id` and `manufacturer_id` 
     # columns always contain a value in the range 0..50. That means 
     # `rake db:populate` will only actually work the first time, but 
     # I think you get the idea of how this should work. 
     10.times{Factory.create(:item, :seller_id => (rand(50) + 1), :manufacturer_id => (rand(50) + 1))} 
     print (['\\', '/', '_', '|'])[rand(4)] 
    end 

    puts "" 
    end 
end 
+0

あなたの入力に感謝が、残念ながら。答えをGoogleに伝えることも助けにはならない。上記の私の詳細を見ましたか? item.manufacturerはベンダーオブジェクトを返しますが、nameなどのベンダーメソッドには応答できません。 – jmil

+0

私はちょうど正しい方向にあなたを指すことを望んで、これに答える私の電話の上にあります。私は明日これを詳しく見て、私の答えを洗練させます。心配しないでください - 私はまだやっていません。 – jefflunt

+0

大変ありがとう! – jmil

関連する問題