Skip to content

Commit

Permalink
Updated README
Browse files Browse the repository at this point in the history
  • Loading branch information
stex committed Jun 3, 2015
1 parent 5c4fd38 commit 76e4dd8
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 15 deletions.
154 changes: 141 additions & 13 deletions README.md
Expand Up @@ -5,14 +5,15 @@ Sometimes it's handy to keep track of various settings or attributes in ActiveRe

The only problem is, that it would be necessary to either keep hundreds of columns in the corresponding table or create a serialized attribute which would grow over time and generally be hard to manage.

This gem consists of a global key-value-store, allowing to use both global and record bound settings.
This gem consists of a global key-value-store, allowing to use both global and record bound settings
and ActiveRecord integration to add virtual columns to models without having to change the database layout.

Installation
------------

Add this line to your application's Gemfile:

```
```ruby
gem 'setting_accessors'
```

Expand Down Expand Up @@ -43,20 +44,18 @@ $ rails g setting_accessors:install MODEL_NAME

If no model name is given, the default one (`Setting`) is used.

Usage
Usage as a global key-value-store (globally defined and anonymous settings)
-----

In the following, the model name will be assumed as `Setting`, though you may choose its name freely using the provided generator (see above).

Settings can either be global or assigned to an instance of ActiveRecord::Base. They consist of a name which is unique either in the global scope or within the instance and a value which can be everything that's serializable through YAML.

### Usage as global key-value-store without predefined settings

The easiest way to use the settings model is as a global key-value-store without validations and typecasting.

Values can be easily set and retrieved by using their names as class method names on `Setting` itself:

```
```ruby
Setting.the_meaning_of_life = 42
Setting.the_meaning_of_life
#=> 42
Expand All @@ -66,16 +65,16 @@ If the name contains characters which are not allowed due to ruby naming rules,

Therefore, the following getter methods are equivalent:

```
```ruby
Setting.meaning_of_life
Setting[:meaning_of_life]
Setting.get(:meaning_of_life)
```

For the corresponding setters:

```
Setting.meaning_of_life = 42
```ruby
Setting.meaning_of_life = 42
Setting[:meaning_of_life] = 42
Setting.create_or_update(:meaning_of_life, 42)
```
Expand All @@ -91,7 +90,7 @@ As stated above, the initializer will generate a file called `settings.yml` in y

An example would be a simple string setting:

```
```yaml
a_string:
type: string
default: "I am a string!"
Expand All @@ -101,20 +100,149 @@ a_string:

If a setting is defined with a type, automatic type conversion will happen, similar to what ActiveRecord does:

```
```ruby
Setting.a_string = 42
#=> "42"
```

The default value is used by the functions `Setting.get_or_default` and `Setting.create_default_setting` and a fallback option for assigned settings (see below).

Validations currently only support
The built-in validations currently support, this might be extended in the future.

| Base Validation | Options |
|:----------------|:---------------------------|
| `presence` | `allow_nil`, `allow_blank` |
| `numericality` | `only_integer` |
| `boolean` | |
| `boolean` |   |


### Assigned Records

Both globally defined settings and "anonymous" settings can also be assigned to
a instances of `ActiveRecord::Base` without having to define them in the model first.

An example would be the above mentioned saving of "items per page" values for
various views: Let's say we have an events view and want to save how many
rows/items each user would like to display.

As there might be many views requiring this functionality, it wouldn't make
sense to define global settings for each of them. Instead, we would use anonymous
settings with a generated key based on the current view:

```ruby
def items_per_page
key = [controller_path, action_name].join('_')
default_value = 30
Setting.get(key, current_user) || default_value
end
```

ActiveRecord Integration
------------------------

The gem adds the method `setting_accessor` to each class which inherits from `ActiveRecord::Base`.

`setting_accessor` takes a setting name and a set of options to customize the accessor's behaviour:

```ruby
class MyModel < ActiveRecord::Base
setting_accessor :a_string, :fallback => :default
end
```

This automatically adds most of the helper methods to the model instances which are available for database columns:

```ruby
my_model = MyModel.new

#Setter
my_model.a_string = 1234

#Getter
my_model.a_string
#=> "1234"

#Value before type cast
my_model.a_string_before_type_cast
#=> 1234

#Old value
my_model.a_string_was
#=> "I am a string!" (fallback value, see below)

#Check if the value was changed
my_model.a_string_changed?
#=> true
```

The setting records are only persisted if all settings *and* the main record were valid.

### Integration of globally defined settings

If a setting with the given name is defined in `config/settings.yml`, validations and type settings are automatically fetched from it, in this case, only the `:fallback` option is allowed.

As of now, this means that custom validations are also not supported for globally defined settings, this may be changed in the future.

### Class-wise definition of settings

If a setting is defined using `setting_accessor` which is not part of `config/settings.yml`, it will only be available in this class. It however may be defined in multiple classes independently.

Defining a class setting accepts the same options as the config file:

```ruby
class MyModel < ActiveRecord::Base
setting_accessor :my_setting, :type => :boolean, :default => false
end
```

### Options

```ruby
:type => :string | :integer | :boolean | :polymorphic
```

`:type` defines the setting's data type. If no type is given, `:polymorhpic`
is used automatically.

For every other type, the setting's value is automatically converted accordingly
upon setting it, mimicking ActiveRecord's behaviour regarding database columns.
Please note that `:polymorphic` values are saved as is, meaning that you can
store everything that's serializable.

More types will be added in the future, most likely all database types
ActiveRecord can handle as well.

```ruby
:default => "I am a string!"
```

`:default` sets the setting's default value. It can be retrieved either by
calling `Setting.get_or_default(...)` or defining a `:fallback` on a class setting.

```ruby
:fallback => :global | :default | Object
```

The `:fallback` option specifies which value should be returned in case the
setting did not receive a value yet:

- `:global` will try to retrieve a global setting (`Setting.NAME`) with the same
name as the accessor and return `nil` if it isn't defined.
- `:default` will return the default value set up either in the accessor method
or `config/settings.yml` for globally defined settings.
- Every other value will be returned as is


```ruby
:validations => {:presence => true}
:validations => {:numericality => {:only_integer => true}}
:validations => {:custom => [lambda {|setting| setting.errors.add(:not_42) if setting.value != 42}]}
:validations => {:custom => [:must_be_42]}
```

There are some built-in validations (see above), but you may also define custom
validations either by passing in anonymous functions or symbols representing
class methods either in the setting class or the assigned model.

Contributing
------------
Expand Down
File renamed without changes.
5 changes: 3 additions & 2 deletions setting_accessors.gemspec
Expand Up @@ -8,8 +8,9 @@ Gem::Specification.new do |spec|
spec.version = SettingAccessors::VERSION
spec.authors = ["Stefan Exner"]
spec.email = ["stex@sterex.de"]
spec.summary = %q{Attributes without database changes. The future? (JK)}
spec.description = %q{Longer description.}
spec.summary = %q{A global key-value-store and virtual model columns}
spec.description = %q{Adds a global key-value-store to Rails applications and allows adding typed columns
to model classes without having to change the database layout.}
spec.homepage = 'https://www.github.com/stex/setting_accessors'
spec.license = "MIT"

Expand Down

0 comments on commit 76e4dd8

Please sign in to comment.