Active Record Nested Attributes

通过嵌套属性(nested attribute),你可以通过parent来保存与其相关联的属性。默认情况下,嵌套属性是关闭的,你可以开启accepts_nested_attributes_for这个类方法,就在该model上生成一个属性writer。
属性writer是以该关联命名。例如,为你的model增加两个新方法:
author_attributes=(attributes) 和 pages_attributes=(attributes).

class Book < ActiveRecord::Base
has_one :author
has_many :pages
accepts_nested_attributes_for :author, :pages
end

使用了accepts_nested_attributes_for的每一个关联都自动开启:autosave


一对一关联
一个Member有一个Avatar(化身):

class Member < ActiveRecord::Base
has_one :avatar
accepts_nested_attributes_for :avatar
end

开启一对一关联的嵌套属性可以通过这样方法一次性创建Member:

params = { :member => { :name => 'Jack', :avatar_attributes => { :icon => 'smiling' } } }
member = Member.create(params[:member])
member.avatar.id # => 2
member.avatar.icon # => 'smiling'

也可以这样update avatar

params = { :member => { :avatar_attributes => { :id => '2', :icon => 'sad' } } }
member.update_attributes params[:member]
member.avatar.icon # => 'sad'

默认情况下你只能设置或更新关联的model。如果你想通过属性hash来删除关联model,你需要使用:allow_destroy 选项

class Member < ActiveRecord::Base
has_one :avatar
accepts_nested_attributes_for :avatar, :allow_destroy => true
end

此时,如果向属性hash里增加一个_destroy的key,并且value是true,则该关联model将被删除:

member.avatar_attributes = { :id => '2', :_destroy => '1' }
member.avatar.marked_for_destruction? # => true
member.save
member.reload.avatar # => nil

注意这里,只有当parent被保存后,关联的model才真正被删除。

--------------------------------------------------------------------

一对多关联
一个member有一些post

class Member < ActiveRecord::Base
has_many :posts
accepts_nested_attributes_for :posts
end

你可通过属性hash来增加或更新关联post model
每一个不含有id键的新记录会被实例化,除非该hash也包含了一个 :_destroy => true

params = {
:member => {
:name => 'joe', :posts_attributes => [
{ :title => 'Kari, the awesome Ruby documentation browser!' },
{ :title => 'The egalitarian assumption of the modern citizen'},
{ :title => '', :_destroy => '1' } # 该记录会被忽略
]
}
}
member = Member.create(params['member'])
member.posts.length # => 2
member.posts.first.title # => 'Kari, the awesome Ruby documentation browser!'
member.posts.second.title # => 'The egalitarian assumption of the modern citizen'

通过 :reject_if proc 设置忽略的不满足条件的记录。例如:

class Member < ActiveRecord::Base
has_many :posts
accepts_nested_attributes_for :posts,
:reject_if => proc { |attributes| attributes['title'].blank? }
end

params = { :member => {
:name => 'joe', :posts_attributes => [
{ :title => 'Kari, the awesome Ruby documentation browser!' },
{ :title => 'The egalitarian assumption of the modern citizen' },
{ :title => '' } # 这个记录会被忽略
]
}
}

member = Member.create(params['member'])
member.posts.length # => 2
member.posts.first.title # => 'Kari, the awesome Ruby documentation browser!'
member.posts.second.title # => 'The egalitarian assumption of the modern citizen'

:reject_if 也可一接受一个symbol来代表一个可用方法:

如果hash中含有一个id和已有的关联记录相匹配,则被匹配到的记录会被修改:

member.attributes = {
:name => 'Joe',
:posts_attributes => [
{ :id => 1, :title => '[UPDATED] An, as of yet, undisclosed awesome Ruby documentation browser!' },
{ :id => 2, :title => '[UPDATED] other post' }
]
}

member.posts.first.title # => '[UPDATED] An, as of yet, undisclosed awesome Ruby documentation browser!'

member.posts.second.title # => '[UPDATED] other post'


默认关联记录是被保护的(不被删除)。如果想通过属性hash来删除任何关联记录,你需要打开:allow_destroy选项, 这样使用_destroy键来删除记录就行:

class Member < ActiveRecord::Base
has_many :posts
accepts_nested_attributes_for :posts, :allow_destroy => true
end

params = { :member => {
:posts_attributes => [{ :id => '2', :_destroy => '1' }]
}
}

member.attributes = params['member']

member.posts.detect { |p| p.id == 2 }.marked_for_destruction? # => true 标记将被删除

member.posts.length # => 2 未保存,所以还没删除
member.save
member.reload.posts.length # => 1

----------------------------------------------------------------------

使用attr_accessible
使用attr_accessible如果不小心,可能会干扰到嵌套属性的使用。例如,上述member model如下使用attr_accessible:

attr_accessible :name
你需要这样的修改:
attr_accessible :name, :posts_attributes


验证parent model 的存在


如果你想验证一个child记录是否和一个parent记录关联,你可以使用validates_presence_of和inverse_of:

class Member < ActiveRecord::Base
has_many :posts, :inverse_of => :member
accepts_nested_attributes_for :posts
end

class Post < ActiveRecord::Base
belongs_to :member, :inverse_of => :posts
validates_presence_of :member
end
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值