cirandas.net

ref: master

vendor/plugins/acts_as_versioned/README.md


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
## About ##
=====

acts_as_versioned is a gem for Rails 3.1 & 3.2 to enable easy versioning of models. As a versioned model is updated revisions are kept in a seperate table, providing a record of what changed.

## Getting Started ##
=====

In your Gemfile simply include:

    gem 'acts_as_versioned', :git => 'https://github.com/jwhitehorn/acts_as_versioned.git'
    
The next time you run `bundle install` you'll be all set to start using acts_as_versioned.  

## Usage ##
=====

#### Versioning a Model ####
By default acts_as_versioned is unobtrusive. You will need to explicitly state which models to version. To do so, add the line `acts_as_versioned` to your model, like so:

    class MyModel < ActiveRecord::Base
      acts_as_versioned
      #...
    end
    
Next we need to create a migration to setup our versioning tables:

    bundle exec rails generate migration AddVersioningToMyModel
    
Once that is completed, edit the generated migration. acts_as_versioned patches your model to add a `create_versioned_table` and `drop_versioned_table` method. A migration for `MyModel` (assuming MyModel already existed) might look like:

    class AddVersioningToMyModel < ActiveRecord::Migration
      def self.up
        MyModel.create_versioned_table
      end

      def self.down
        MyModel.drop_versioned_table
      end
    end

Execute your migration:
    
    bundle exec rake db:migrate
    
And you're finished! Without any addition work, `MyModel` is being versioned.

#### Excluding attributes from versioning  ####

Sometime you want to exclude an attribute of a model from being versioned. That can be accomplished with the `:except` paramter to `acts_as_versioned`:

    class MyMode < ActiveRecord::Base
      acts_as_versioned :except => :some_attr_i_dont_want_versioned
      
    end


#### Revisions ####

Recording a history of changes to a model is only useful if you can do something with that data. With acts_as_versioned there are several ways you can interact with a model's revisions.

##### Version Number #####
To determine what the current version number for a model is:

    model.version

The `version` attribute is available for both the actual model, and also any revisions of a model. Thusly, the following is valid:

    model.versions.last.version

##### Revisions List #####
As alluded to above, you can get an array of revisions of a model via the `versions` attribute:

    model.versions
    
The returned objects are of a type `MyModel::Version` where `MyModel` is the model you are working with. These objects have identical fields to `MyModel`. So, if `MyModel` had a `name` attribute, you could also say:

    model.versions.last.name

##### Reverting to a Revision #####
To revert a model to an older revision, simply call `revert_to` with the version number you desire to rever to:

    model.revert_to(version_number)

##### Saving Without Revisions #####
Occasionally you might need to save a model without necessary creating revisions. To do so, use the `save_without_revision` method:
    
    model.save_without_revision


#### Migrations ####
Adding a field to your model does not automatically add it to the versioning table. So, when you add new fields, be sure to add them to both:

    class AddNewFieldToMyModel < ActiveRecord::Migration
      def change
        add_column :my_models, :new_field_, :string
        add_column :my_model_versions, :new_field_, :string
      end
    end

#### Version Class ####
As has been stated, the versioned data is stored seperately from the main class. This also implies that `model.versions` returns an area of object of a class _other_ than `MyModel` (where `model` is an instance of `MyModel`, keeping with our working example). The instances returned are actually of type `MyModel::Version`. With this, comes the fact that any methods, associations, etc. defined on `MyModel` are not present on `MyModel::Version`.

While this sounds obvious, it can some times be unexpected. Especially when acts_as_versioned make it so easy to grab historical records from a live record. A common scenario where this can come up is associations.

Say `MyModel` belongs to `TheMan`. Also, assume that you want to find out where (in the past) a particular instance of `MyModel` was updated in regards to it's association to `TheMan`. You could write that as:  
    
    model.versions.keep_if { |m| m.the_man != current_man }.last
    
However, this will not work. This is because `MyModel::Version` does _not_ belong to `TheMan`. You could compare ids here, or you could patch `MyModel::Version` to belong to `TheMan` like:

    class MyModel
      acts_as_versioned
      belongs_to :the_men
      #some stuff
      
      class Version
        belongs_to :the_men
      end
    end