2012-01-08 54 views
3

我有两个表。项目和供应商。项目由供应商销售。所以物品belongs_to:供应商和供应商has_many:物品。这工作正常。Rails 3.1高级Has_many和belongs_to模型连接

但是,物品并不总是由销售他们的厂商制造,但有时他们是。所以我在我的Item表中有一个名为“manufacturer_id”的新列。我试图做一个复杂的has_many和belongs_to来定义制造商,而不是生成一个名为Manufacturer的新模型。

在这里看到:

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 

表工作正常上创建命令的物品填充MANUFACTURER_ID:

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 

因此item.manufacturer.name应该返回上述供应商对象的名称,供应商:0x007ff06684e398。

我在这里做错了什么?

而且,一旦我得到这个工作,我希望能够同样拨打:

vendor.manufactured_items 

让所有有供应商的MANUFACTURER_ID的项目。有没有一种简单的方法可以做到这一点?

我最后的努力,可能涉及不必做:

制造商= Vendor.new(item.manufacturer)

但是,这似乎完全错误的,违背了Rails文档浏览: 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文件,它具有我运行的控制台会话输出以显示其工作。您还需要查看两个模型类,以及它们的关联如何定义,以及如何设置假数据库数据(我已包括下面的那些文件)的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

感谢您的输入,但不幸的是这并没有解决我的问题。告诉我谷歌的答案也没有帮助。你有没有看到我上面描述的细节? item.manufacturer返回一个供应商对象,但它不能响应供应商的方法,如名称。 – jmil 2012-01-08 04:41:44

+0

我只是在我的电话中回答这个问题,希望能指出您正确的方向。我将在明天仔细研究这一点并改进我的答案。别担心 - 我还没有完成。 – jefflunt 2012-01-08 05:38:56

+0

好,非常感谢! – jmil 2012-01-08 07:37:40

相关问题