我有一个类似的模型:
class Content < ActiveRecord::Base
has_many :revisions
end
class Revision < ActiveRecord::Base
belongs_to :Content
end
在我的控制器中我正在做:
def create
@content = Content.new(content_params)
if @content.save
# ...
end
end
内容有:
- id
- category_id
- title
- body
- ..
修订版已经:
- id
- category_id
- content_id
- body
因此,每当我保存/更新/删除内容时,修订版都会发生同样的事情。
我应该使用相同的方法创建一个before_save来处理这两种情况吗? 如何轻松地将category_id,content_id和body传递给Revision?
更新
在更新期间,如果我要更新特定的revision_id,我必须拥有该revision_id但不确定在更新Content实例时如何传递它。这有意义吗?
答案 0 :(得分:1)
我可以看看ActiveRecord::Callbacks。以下是如何使用它们的示例:
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
一般来说,我不喜欢使用回调创建另一个模型的想法。这感觉违反了单一责任原则。您可以使用服务对象来处理您提到的创建和更新操作。
请注意dependent: destroy
关系中的has_many
语法,如上面的代码块所示。这会将Content
记录的删除级联到其相关的Revision
。
<强>更新强>
如果您只想更新控制器内的特定版本,可以写:
def create
@content = Content.new(content_params)
if @content.save
Revision.find(revision_id).update_attributes!(...)
end
end
答案 1 :(得分:0)
您问题的直接答案是使用before_update
回调,或与inverse_of
(因此相关对象在内存中可用):
#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
每次revision
update
模型时,上述内容都会创建一个新的content
。两者都会在您使用accepts_nested_attributes_for
作为推荐,可能希望查看Paper Trail
gem。
这完全您正在寻找的内容(就修订而言) - 它会保存您在模型上执行的所有更新/修改。
#Gemfile
gem 'paper_trail'
$ rails generate paper_trail:install
$ rake db:migrate
#app/models/content.rb
class Content < ActiveRecord::Base
has_paper_trail
end
这将自动记录对执行它的模型和的更改。