gem install extend_at
### Rails 3
Add in your Gemfile:
gem 'extend_at'
After that, you need execute:
rails generate extend_at:install
This will generate one migration with all necessary tables.
## Usage
You don't need an extra column in your model. Only you need is put next code in your model.
extend_at :extra
For example:
class User < ActiveRecord::Base
extend_at :extra
end
Now you can create extra attributes:
user.extra.private_photos = true
user.extra.subscribe_to_news = false
user.extra.profile_description = ''
user.save
This is the same:
user.extra_private_photos = true
user.extra_subscribe_to_news = false
user.extra_profile_description = ''
user.save
Or:
user[:extra_private_photos] = true
user[:extra_subscribe_to_news] = false
user[:extra_profile_description] = ''
user.save
### Columns configuration
You can configure each column.
#### Set column type
You can set the colum's type.
class User < ActiveRecord::Base
extend_at :extra, :columns => {
:private_photos => {
:type => :boolean
}, :age => {
:type => :get_type
}, :profile_description => {
:type => lambda {
String
}
}, :last_loggin => {
:type => Time.now.class
}, :subscribe_to_rss => :get_rss_config
}
protected
def get_type
Fixnum
end
def get_rss_config
{
:type => :boolean
}
end
end
##### Valid types
Valid symbols:
* :any
* :binary
* :boolean
* :date
* :datetime
* :decimal
* :float
* :integer
* :string
* :text
* :time
* :timestamp
But you can use classes.
* Float: :any
* Fixnum: :integer
* String: :text
* Time: :timestamp
* Date: :datetime
Else, return :any
#### Set default value
class User < ActiveRecord::Base
extend_at :extra, :columns => {
:private_photos => {
:type => :boolean,
:default => true
}, :age => {
:type => :get_type,
:default => 1
}, :profile_description => {
:type => lambda {
String
},
:default => :get_default_profile_description
}, :last_loggin => {
:type => Time.now.class,
:default => lambda {
self.created_at.time
}
}, :subscribe_to_rss => :get_rss_config
}
protected
def get_type
Fixnum
end
def get_rss_config
{
:type => :boolean,
:default => true
}
end
def get_default_profile_description
Description.where(:user_id => self.id).default
end
end
#### Set validation
class User < ActiveRecord::Base
extend_at :extra, :columns => {
:private_photos => {
:type => :boolean,
:default => true
}, :age => {
:type => :get_type,
:default => 1,
:validate => lambda {
|age|
errors.add :extra_age, "Are you Matusalen?" if age > 150
errors.add :extra_age, "Are you a fetus?" if age <= 0
}
}, :profile_description => {
:type => lambda {
String
},
:default => :get_default_profile_description,
:lambda => :must_not_use_strong_language
}, :last_loggin => {
:type => Time.now.class,
:default => lambda {
self.created_at.time
},
:validate => lambda {
|time|
errors.add :extra_last_loggin, "You can't loggin on the future" if time > Time.now
}
}, :subscribe_to_rss => :get_rss_config
}
protected
STRONG_WORD = [
#...
]
def get_type
Fixnum
end
def get_rss_config
{
:type => :boolean,
:default => true
}
end
def get_default_profile_description
Description.where(:user_id => self.id).default
end
def must_not_use_strong_language(desc)
errors.add :cofig_profile_description, "You must not use strong language" if desc =~ /(#{STRONG_WORD.join('|')})/
end
end
### Static columns
If you like to restrict the existent extended columns, you should use :static => true
class User < ActiveRecord::Base
extend_at :extra, :columns => {
:private_photos => {
:type => :boolean,
:default => true
}
}, :static => true
end
Now, User.extra
only accept private_photos
column
### Scopes
You can use scope like:
User.extra_last_loggin_gt_eq(1.week.ago).extra_age_gt_eq(18).where(:column => "value").all
Valid scopes:
:extra_name
, for example:
<% form_for(@user) do |f| %>
...