我正在尝试让一个父/子has_many / belongs_to关系在rails中工作。这似乎比更典型的模型更棘手。我是Rails的新手,请原谅我,如果这看起来像一个非常简单的问题。 这是我的模特:
class Category < ActiveRecord::Base
has_many :subcategories, class_name: "Category", foreign_key: "parent_id", dependent: :destroy
belongs_to :parent, class_name: "Category", foreign_key: "parent_id"
end
这就是创建对象的正确方法:
parent = Category.new(name: 'animal')
child = parent.subcategories.build(name: 'cat')
parent.subcategories #this works fine
child.parent #this returns nil
我发现作品的唯一方法是添加child.parent = parent
,但这似乎不是正确的做法。
编辑:
这是我正在使用的rspec测试和输出
require 'rails_helper'
RSpec.describe Category, type: :model do
context "Category" do
before(:all) do
@parent = Category.new(name: 'animal')
@child = @parent.subcategories.build(name: 'cat')
end
it "should equal subcategory" do
expect(@parent.subcategories.first).to eq(@child)
end
it "should reference to parent" do
expect(@child.parent).to eq(@parent)
end
end
end
结果
21:44:56 - INFO - Running: spec/models/category_spec.rb
.F
Failures:
1) Category Category should reference to parent
Failure/Error: expect(@child.parent).to eq(@parent)
expected: #<Category id: nil, name: "animal", parent_id: nil, created_at: nil, updated_at: nil>
got: nil
(compared using ==)
# ./spec/models/category_spec.rb:14:in `block (3 levels) in <top (required)>'
Finished in 0.02808 seconds (files took 3.48 seconds to load)
2 examples, 1 failure
Failed examples:
rspec ./spec/models/category_spec.rb:13 # Category Category should reference to parent
答案 0 :(得分:3)
我认为问题是您的父母尚未保存。改变这个:
@parent = Category.new(name: 'animal')
以下内容:
@parent = Category.create(name: 'animal')
答案 1 :(得分:3)
因此,经过一些(好一堆)搜索ActiveRecord的时间之后,我就找到了。
假设:
class create_category_table < ActiveRecord::Migration
def change
create_table :categories do |t|
t.integer :parent_id
end
end
end
class Category < ActiveRecord::Base
has_many :sub_categories, class: Category, foreign_key: :parent_id
belongs_to :parent, class: Category
end
@parent = Category.new
@child = @parent.sub_categories.build
基本上@child.parent
返回nil
的原因是因为当新记录通过@parent.sub_categories
方法添加到#build
时,活动记录无法知道has_many关联的反向关系是。这是因为我们给他们起名字,&#34; sub_categories&#34;和&#34; parent&#34;,不能通过类名中的活动记录派生。活动记录允许您添加:class
和:foreign_key
选项,以阐明在实例化相关对象时要使用的类以及在查找记录时要查找的foreign_key。但它特别不会为关系创建反向反射(在#build
中添加记录时关联会查找该反转),因为:foreign_key
位于INVALID_AUTOMATIC_INVERSE_OPTIONS
数组中。
除此之外还有更多内容,但是从这次探索中,我发现了一个非常简单的解决方案,那就是明确声明反射的反名称。
在关联下方添加此代码,您可以查找@parent.sub_categories
和@child.parent
没有 持久保存数据库中的任何记录:
reflections["sub_categories"].options[:inverse_of] = :parent
reflections["parent"].options[:inverse_of] = :sub_categories
或(我真的希望我没有在这上面浪费很多时间),只需在关联选项中添加:inverse_of
选项:
class Category < ActiveRecord::Base
has_many :sub_categories, class: Category, foreign_key: :parent_id, inverse_of: :parent
belongs_to :parent, class: Category, inverse_of: :sub_categories
end
Aaaaaaaaaaaaannd发现了所有这些之后,这里有明确解释的文档:(http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html)
...
答案 2 :(得分:1)
belongs_to
关系不需要foreign_key
属性。请参阅:http://guides.rubyonrails.org/association_basics.html#self-joins
答案 3 :(得分:1)
明显的build
是ActiveRecord association
方法。因此它最终会在构建期间保持关联。但是new
对象并不知道关联。所以它反映了nil
。
你的加入是完美的。