考虑以下代码
class CreateFoosAndBars < ActiveRecord::Migration
def change
create_table :foos do |t|
t.string :name
t.timestamps
end
create_table :bars do |t|
t.integer :foo_id
t.string :name
t.timestamps
end
end
end
class Foo < ActiveRecord::Base
has_many :bars
end
class Bar < ActiveRecord::Base
belongs_to :foo
validates_presence_of :foo
end
因此,没有foo,foos可以有任意数量的条形和条形。
此代码应保存,但不会:
irb(main):020:0> foo = Foo.new
=> #<Foo id: nil, name: nil, created_at: nil, updated_at: nil>
irb(main):021:0> foo.bars.build
=> #<Bar id: nil, foo_id: nil, name: nil, created_at: nil, updated_at: nil>
irb(main):022:0> foo.save
(0.2ms) BEGIN
(0.2ms) ROLLBACK
=> false
irb(main):023:0> foo.errors
=> #<ActiveModel::Errors:0x007fb325b35e68 @base=#<Foo id: nil, name: nil, created_at: nil, updated_at: nil>, @messages={:bars=>["er ikke gyldig"]}>
irb(main):024:0>
我正在为这个项目使用Rails 4.0.3。
我似乎无法掌握如何以事务方式初始化,验证和保存具有多个条形的foo。我在这里缺少什么?
答案 0 :(得分:3)
您的代码应该可以使用,我将您的示例粘贴到新的rails应用程序中:
class CreateFoosAndBars < ActiveRecord::Migration
def change
create_table :foos do |t|
t.string :name
t.timestamps
end
create_table :bars do |t|
t.integer :foo_id
t.string :name
t.timestamps
end
end
end
class Foo < ActiveRecord::Base
has_many :bars
end
class Bar < ActiveRecord::Base
belongs_to :foo
validates_presence_of :foo
end
这些是结果:
2.1.1 :001 > Foo.count
(0.1ms) SELECT COUNT(*) FROM "foos"
=> 0
2.1.1 :002 > Bar.count
(0.1ms) SELECT COUNT(*) FROM "bars"
=> 0
2.1.1 :003 > foo = Foo.new
=> #<Foo id: nil, name: nil, created_at: nil, updated_at: nil>
2.1.1 :004 > foo.bars.build
=> #<Bar id: nil, foo_id: nil, name: nil, created_at: nil, updated_at: nil>
2.1.1 :005 > foo.save
(0.3ms) SAVEPOINT active_record_1
SQL (0.5ms) INSERT INTO "foos" ("created_at", "updated_at") VALUES (?, ?) [["created_at", "2014-06-21 16:24:15.334535"], ["updated_at", "2014-06-21 16:24:15.334535"]]
SQL (0.2ms) INSERT INTO "bars" ("created_at", "foo_id", "updated_at") VALUES (?, ?, ?) [["created_at", "2014-06-21 16:24:15.342524"], ["foo_id", 1], ["updated_at", "2014-06-21 16:24:15.342524"]]
(0.1ms) RELEASE SAVEPOINT active_record_1
=> true
2.1.1 :006 > foo.errors
=> #<ActiveModel::Errors:0x007ff37b9514a8 @base=#<Foo id: 1, name: nil, created_at: "2014-06-21 16:24:15", updated_at: "2014-06-21 16:24:15">, @messages={}>
2.1.1 :007 > Foo.count
(0.2ms) SELECT COUNT(*) FROM "foos"
=> 1
2.1.1 :008 > Bar.count
(0.3ms) SELECT COUNT(*) FROM "bars"
=> 1
这是使用Rails 4.1.0。
在4.1.0之前的Rails版本中,您必须指定以下关系:
class Foo
has_many :bars, inverse_of: :foo
end
然而,Rails 4.1.0现在启发式地检测到反向关联,如记录here。
答案 1 :(得分:0)
foo = Foo.build
bar = foo.bars.build
bar.save
原因是你在不保存foo的情况下创建条形图。因此foo无效。你必须先保存foo,这样才能得到一个id。
更新:
你必须在你的酒吧模型中使用inverse_of。
belongs_to :foo, inverse_of :bar
Foo模型
has_many :bards, inverse_of :foo
参考:http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html
答案 2 :(得分:0)
尝试将inverse_of选项添加到两个关联中。也许Rails在某个地方变得混乱,无法与之匹敌。
答案 3 :(得分:0)
我发现了解决方案。
如果我这样做
foo = Foo.new
bar = foo.bars.build
bar.foo
=> nil
所以build
撒谎。它并没有像你期望的那样建立一个与foo相关联的栏。 build
仅在foo持久化时有效。
但是,如果我将inverse_of: :foo
添加到我的Foo模型关联中,如下所示:
class Foo < ActiveRecord::Base
has_many :bars, inverse_of: :foo
end
它突然奇怪的工作。在构建的条形实例上调用foo
会突然返回一个对象而不是nil。
irb(main):002:0> bar = foo.bars.build
=> #<Bar id: nil, foo_id: nil, name: nil, created_at: nil, updated_at: nil>
irb(main):003:0> bar.foo
=> #<Foo id: nil, name: nil, created_at: nil, updated_at: nil>
irb(main):005:0> bar.foo.object_id
=> 70208007135620
irb(main):006:0> foo.object_id
=> 70208007135620
我不知道为什么这是必要的而不是默认行为。
此问题仅适用于4.1.0之前的Rails版本。