打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
【译】rails的嵌套属性(Nested Attributes)使用

 

Active Record Nested Attributes通过嵌套属性(nested attribute),你可以通过parent来保存与其相关联的属性。默认情况下,嵌套属性是关闭的,你可以开启accepts_nested_attributes_for这个类方法,就在该model上生成一个属性writer。属性writer是以该关联命名。例如,为你的model增加两个新方法:author_attributes=(attributes) 和 pages_attributes=(attributes).
Ruby代码  
  1.  class Book < ActiveRecord::Base  
  2.     has_one :author  
  3.     has_many :pages  
  4.   
  5.     accepts_nested_attributes_for :author:pages  
  6. end  
 使用了accepts_nested_attributes_for的每一个关联都自动开启:autosave
一对一关联
一个Member有一个Avatar
Ruby代码  
  1. class Member < ActiveRecord::Base  
  2.   has_one :avatar  
  3.   accepts_nested_attributes_for :avatar  
  4. end  
 开启一对一关联的嵌套属性可以通过这样方法一次性创建Member

 

Ruby代码  
  1. params = { :member => { :name => 'Jack':avatar_attributes => { :icon => 'smiling' } } }  
  2. member = Member.create(params[:member])  
  3. member.avatar.id # => 2  
  4. member.avatar.icon # => 'smiling'  
  5.   
  6. 也可以这样update avatar  
  7.   
  8. params = { :member => { :avatar_attributes => { :id => '2':icon => 'sad' } } }  
  9. member.update_attributes params[:member]  
  10. member.avatar.icon # => 'sad'  
 默认情况下你只能设置或更新关联的model。如果你想通过属性hash来删除关联model,你需要使用:allow_destroy 选项
Ruby代码  
  1. class Member < ActiveRecord::Base  
  2.   has_one :avatar  
  3.   accepts_nested_attributes_for :avatar:allow_destroy => true  
  4. end  
 此时,如果向属性hash里增加一个_destroykey,并且valuetrue,则该关联model将被删除。
Ruby代码  
  1. member.avatar_attributes = { :id => '2', :_destroy => '1' }  
  2. member.avatar.marked_for_destruction? # => true  
  3. member.save  
  4. member.reload.avatar # => nil  
 注意这里,只有当parent被保存后,关联的model才真正被删除。
一对多关联
一个member有一些post
Ruby代码  
  1. class Member < ActiveRecord::Base  
  2.   has_many :posts  
  3.   accepts_nested_attributes_for :posts  
  4. end  
 你可通过属性hash来增加或更新关联post model每一个不含有id键的新记录会被实例化,除非该hash也包含了一个 :_destroy => true
Ruby代码  
  1. params = {   
  2.   :member => {  
  3.   
  4.     :name => 'joe':posts_attributes => [  
  5.   
  6.       { :title => 'Kari, the awesome Ruby documentation browser!' },  
  7.       { :title => 'The egalitarian assumption of the modern citizen' },  
  8.       { :title => '', :_destroy => '1' } # 该记录会被忽略  
  9.     ]  
  10.   }  
  11. }  
  12. member = Member.create(params['member'])  
  13. member.posts.length # => 2  
  14. member.posts.first.title # => 'Kari, the awesome Ruby documentation browser!'  
  15. member.posts.second.title # => 'The egalitarian assumption of the modern citizen'  
 通过 :reject_if proc 设置忽略的不满足条件的记录。例如:
Ruby代码  
  1. class Member < ActiveRecord::Base  
  2.    has_many :posts  
  3.    accepts_nested_attributes_for :posts:reject_if => proc { |attributes| attributes['title'].blank? }  
  4.  end  
  5.   
  6. params = { :member => {  
  7.   :name => 'joe':posts_attributes => [  
  8.     { :title => 'Kari, the awesome Ruby documentation browser!' },  
  9.     { :title => 'The egalitarian assumption of the modern citizen' },  
  10.     { :title => '' } #  这个记录会被忽略  
  11.   ]  
  12. }}  
  13.   
  14. member = Member.create(params['member'])  
  15. member.posts.length # => 2  
  16. member.posts.first.title # => 'Kari, the awesome Ruby documentation browser!'  
  17. member.posts.second.title # => 'The egalitarian assumption of the modern citizen'  
 :reject_if 也可一接受一个symbol来代表一个可用方法:如果hash中含有一个id和已有的关联记录相匹配,则被匹配到的记录会被修改:
Ruby代码  
  1. member.attributes = {  
  2.   :name => 'Joe',  
  3.   :posts_attributes => [  
  4.     { :id => 1, :title => '[UPDATED] An, as of yet, undisclosed awesome Ruby documentation browser!' },  
  5.     { :id => 2, :title => '[UPDATED] other post' }  
  6.   ]  
  7. }  
  8. member.posts.first.title # => '[UPDATED] An, as of yet, undisclosed awesome Ruby documentation browser!'  
  9. member.posts.second.title # => '[UPDATED] other post'  
 默认关联记录是被保护的(不被删除)。如果想通过属性hash来删除任何关联记录,你需要打开:allow_destroy选项, 这样使用_destroy键来删除记录就行:
Ruby代码  
  1. class Member < ActiveRecord::Base  
  2.   has_many :posts  
  3.   accepts_nested_attributes_for :posts:allow_destroy => true  
  4. end  
  5.   
  6. params = { :member => {  
  7.   :posts_attributes => [{ :id => '2', :_destroy => '1' }]  
  8. }}  
  9. member.attributes = params['member']  
  10. member.posts.detect { |p| p.id == 2 }.marked_for_destruction? # => true  标记将被删除  
  11. member.posts.length # => 2  未保存,所以还没删除  
  12. member.save  
  13. member.reload.posts.length # => 1   
 
保存
所有对model修改的行为,包括标记将要销毁,会随着parent被保存原子性的被自动保存或者删除。这些开始与parentsave方法,发生在其内部的事务里。详见 Active Record Autosave Association
使用attr_accessible
使用attr_accessible如果不小心,可能会干扰到嵌套属性的使用。例如,上述member model如下使用attr_accessible
Ruby代码  
  1. attr_accessible :name  
 你需要这样的修改:
Ruby代码  
  1. attr_accessible :name:posts_attributes  
 
验证parent model 的存在

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

Ruby代码  
  1. <span style="font-size: xx-small;">class Member < ActiveRecord::Base  
  2.   has_many :posts:inverse_of => :member  
  3.   accepts_nested_attributes_for :posts  
  4. end  
  5.   
  6. class Post < ActiveRecord::Base  
  7.   belongs_to :member:inverse_of => :posts  
  8.   validates_presence_of :member  
  9. end</span>  
 
具体应用见 http://cn.asciicasts.com/episodes/196-nested-model-form-part-1

 

 

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Rails ---> routes.rb 详解
colGroup HTML元素
ruby系列教材(13):Attributes, Instance Variables, and Methods
avatar
Avatar
mysql之上二级
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服