我写了一个宝石,允许Google Spreadsheets转换为Rails模型。此过程的顺序包括创建所有模型,然后连接它们的关联,然后保存所有模型。它支持所有可用的关联类型,并且在每种情况下都禁止一个,创建模型,建立关联,然后保存模型正常工作。例外情况如下:
我有一个简单的has_one, through
关联(为简洁省略了属性访问):
class Left < ActiveRecord::Base
has_many :middles, dependent: :destroy
has_many :rights, through: :middles
end
class Right < ActiveRecord::Base
has_one :middle, dependent: :destroy
has_one :left, through: :middle
end
class Middle < ActiveRecord::Base
belongs_to :left
belongs_to :right
end
我发现一些不一致的行为取决于关联分配的哪一方:
从右到左分配:
left = Left.new
right = Right.new
left.rights << right
left.middles #[]
right.middle #nil
left.save!
left.middles # <Middle theme_id: 1, archive_resource_id: 1 >
从右到左分配:
left = Left.new
right = Right.new
right.left = left
left.middles #[]
right.middle <Middle theme_id: nil, archive_resource_id: nil >
right.save!
right.middle # <Middle theme_id: nil, archive_resource_id: 1 >
此行为似乎非常不一致。为什么是这样?为什么这种方式是单向的而不是另一种方式?有没有办法与两个未保存的记录建立这种关系?
我很欣赏显而易见的解决方案是在设置关系之前保存所有内容,但如上所述,我需要在建立关联时将模型保存为 ,并且在所有其他类型的协会,这方面没有问题。
答案 0 :(得分:0)
根据Rails API文档(link) -
如果您在联接模型上使用belongs_to,那么最好是 在belongs_to上设置:inverse_of选项,这意味着 以下示例正常工作(其中tags是has_many:through 协会):
因此@Kaleidoscope建立的关联是正确的。
答案 1 :(得分:0)
我认为它没有用,因为你有
has_many - has_one
左右之间的关系,而不是
has_many - belongs_to
另一方面
belongs_to:left,through :: middle
是不可能的。所以你应该使用委托getter和自己写setter方法,像这样
class Right < ActiveRecord::Base
has_one :middle, dependent: :destroy
delegate :left, to: :middle
def left=(left)
#logic
end
end
答案 2 :(得分:-1)
我认为它可能有效,但不会立即更新。在调用关联方法时尝试传递true
。防爆。 right.middle(true)
。这将迫使Rails返回数据库以获取记录,而不是检查缓存,这是陈旧的。但是,不要在新记录上执行此操作,因为您将清除内存中的关联对象。
为避免强制重新加载,请在您的关联上设置inverse_of
:
class Left < ActiveRecord::Base
has_many :middles, dependent: :destroy, inverse_of: :left
has_many :rights, through: :middles
end
class Right < ActiveRecord::Base
has_one :middle, dependent: :destroy, inverse_of: :right
has_one :left, through: :middle
end
class Middle < ActiveRecord::Base
belongs_to :left, inverse_of: :middles
belongs_to :right, inverse_of: :middle
end
inverse_of
使model
知道关联模型与自身的关系,这使得它可以“保持”关于持久化和加载关联对象的“智能”。