Description
Attribute inheritance for ActiveRecord
models
Using attr_inherited
allows your ActiveRecord
models to inherit any of their attributes from an associated, or parent model.
Usage
Inheriting attributes from an associated model
Given a Post
model and the following Version
model
class Version < ActiveRecord::Base
belongs_to :post
attr_inherited :title, :synopsis, from: :post
end
..then Version
will now inherit title
and synopsis
from the parent post, if either attributes are nil
1.9.3p194 :001 > post = Post.create!(title: "First post", synopsis: "First post synopsis")
1.9.3p194 :002 > version = Version.create!(post: post)
1.9.3p194 :003 > version.title
=> "First post"
1.9.3p194 :004 > version.body
=> "First post body"
You can override any of the inherited attributes by setting its a value to anything other than nil
1.9.3p194 :005 > version.update_attributes(description: "Version synopsis")
1.9.3p194 :006 > version.synopsis
=> "Version description"
Renaming inherited attributes
If you want the inherited attribute to have a name other than that of the associated model's attribute, you can use the as:
option to rename it. For example:
class Version < ActiveRecord::Base
belongs_to :post
attr_inherited :synopsis, from: :post, as: :description
end
1.9.3p194 :001 > post = Post.create!(synopsis: "First post synopsis")
1.9.3p194 :002 > version = Version.create!(post: post)
1.9.3p194 :003 > version.description
=> "First post synopsis"
Note that description
must be an attribute of Version
for the above to work.
Inheriting attributes even when they are not nil
You might want to inherit an attribute not only when it is nil
but even when it is an empty string ""
. You can do this by passing a predicate with the when:
option that would test if the attribute should be inherited.
class Version < ActiveRecord::Base
belongs_to :post
attr_inherited :title, from: :post, when: :blank?
end
1.9.3p194 :001 > post = Post.create!(title: "First post")
1.9.3p194 :002 > version = Version.create!(post: post)
1.9.3p194 :003 > version.title
=> "First post"
1.9.3p194 :004 > version.update_attributes(title: " ")
1.9.3p194 :005 > version.title
=> "First post"
Using the when:
option to fake has_many association inheritance
Until real association inheritance is implemented you can fake it like this:
class Version < ActiveRecord::Base
has_many :comments, as: :commentable
end
class Version < ActiveRecord::Base
belongs_to :post
has_many :comments, as: :commentable
attr_inherited :comments, from: :post, when: :empty?
end
...which makes comments
behave almost as if it was inherited from Post
:
1.9.3p194 :001 > post = Post.create!(title: "First post")
1.9.3p194 :002 > post.comments.create(text: "Post comment")
1.9.3p194 :003 > version = Version.create!(post: post)
1.9.3p194 :004 > version.comments.first.text
=> "Post comment"
1.9.3p194 :005 > version.comments = [Comment.create(text: "Version comment")]
1.9.3p194 :006 > version.comments.first.text
=> "Version comment"
Caveat: You can't call any other association methods on version.comments
when it is inherited, such as <<
, .create
, .build
Installation
Requires Rails 3.1+
Add this line to your application's Gemfile:
gem 'attr_inherited'
And then execute:
$ bundle
Or install it yourself as:
$ gem install attr_inherited
Changelog
1.0.0 Initial relase (2012-10-02)
To Do
- Test assertion of valid parameters
- Write rdocs
- Document or remove default
parent
option forfrom:
option - Properly support inheriting associations
- Investigate support for virtual attributes (:attr_accessor)
Contributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request
Copyright (c) Christos Zisopoulos, released under the MIT license