Reputation: 267320
I have a model like:
class Content < ActiveRecord::Base
has_many :revisions
end
class Revision < ActiveRecord::Base
belongs_to :Content
end
In my controller I am doing:
def create
@content = Content.new(content_params)
if @content.save
# ...
end
end
Content has:
- id
- category_id
- title
- body
- ..
Revision has:
- id
- category_id
- content_id
- body
So whenever I save/update/delete a Content the same thing should happened with the Revision.
Should I create a before_save to handle both situations using the same method? How can I easily pass the category_id, content_id and body to the Revision?
Update
During an update, if I am updating a particular revision_id, I have to have that revision_id but not sure how to pass that when I am updating a Content instance. Does that make sense?
Upvotes: 1
Views: 1245
Reputation: 76784
The direct answer to your question is to use a before_update
callback, perhaps with inverse_of
(so the associated objects are available in memory):
#app/models/content.rb
class Content < ActiveRecord::Base
has_many :revisions
accepts_nested_attributes_for :revisions
before_update :set_revision
before_create :set_revision
private
def set_revision
self.revisions.build body: self.body
end
end
#app/models/revision.rb
class Revision < ActiveRecord::Base
belongs_to :content
end
The above will create a new revision
each time you update
your content
model. Both will save as you're using accepts_nested_attributes_for
As a recommendation, you may wish to look at the Paper Trail
gem.
This does exactly what you're looking for (in terms of revisions) -- it saves any updates / edits you perform on a model.
#Gemfile
gem 'paper_trail'
$ rails generate paper_trail:install
$ rake db:migrate
#app/models/content.rb
class Content < ActiveRecord::Base
has_paper_trail
end
This will automatically record the changes to the model and who performed it.
There is a good RailsCast about it here.
Upvotes: 0
Reputation: 191
I might take a look a ActiveRecord::Callbacks. Here is an example for how to use them:
class Content < ActiveRecord::Base
has_many :revisions, dependent: :destroy
after_commit :update_revision
private
def update_revision
# Create or update a revision object
end
end
In general, I don't like the idea of creating another model using callbacks. It feels like a violation of the single responsibility principle. You might use a service object to handle the create and update operations you mentioned.
Note the dependent: destroy
syntax on the has_many
relationship as in the code block above. This will cascade deletes of a Content
record to its related Revision
s.
Update
If you just want to update a specific revision inside your controller, you could write:
def create
@content = Content.new(content_params)
if @content.save
Revision.find(revision_id).update_attributes!(...)
end
end
Upvotes: 2