1

我运行一个类似于 StackOverflow 的网站,用户可以在其中发布内容(帖子)。还有一个首页展示了我们的编辑挑选的特色帖子。

我希望允许我们的用户随时编辑他们的帖子,同时仍然确保没有任何内容出现在我们的首页上,除非它首先由我们的编辑审查。

为了解决这个问题,我想我们可以实现一个版本控制系统,比如在我们发布帖子时paper_trail存储当前版本。version_id通过这种方式,我们可以简单地在首页上获取经过编辑审核的内容,同时仍然在网站的不太重要的部分(例如用户的个人资料)上显示最新版本。我们的编辑可以定期审查任何更改并批准这些更改。

我想知道最干净的方法是什么,它允许我在某些控制器中选择经过审核的版本,在其他控制器中选择最新版本,同时保持共享界面和最少的重复代码。


理想的解决方案将涉及一个reviewed范围,因此我可以简单地执行Post.reviewed并取回已审核的版本,并Post.all获取最新版本。

不过我不知道该怎么做,因为获得审查的版本需要反序列化对象 PaperTrail 存储(version.reify),这在范围内似乎是不可能的。

我可以像这样使用类方法:

def self.reviewed all.map do |post| Version.find(post.version_id).reify end.compact! || Post.none end

但是,这不太理想,因为它不是真正的范围,因此不可链接等。

或者,我可以使用 Post 实例方法,例如:

def reviewed_version Version.find(version_id).reify end

这在理论上可行,但这意味着我现在必须在我的所有视图中调用此方法,而获取正确数据是控制器的责任。假设我render collection: @posts在首页和用户资料上都有一个,我的_post.html.erb部分如何知道是否打电话reviewed_version


我没有绑定到 PaperTrail,但它有很多我不想复制的细节。但是,如果 PaperTrail 太不灵活,我愿意探索其他方向。

FWIW,我也看过Draftsman,但它认为“草稿”是例外(即在大多数情况下,您不会显示草稿),而在我的情况下,我想在大多数页面上显示最新版本,除了像首页这样的少数几个。

4

1 回答 1

1

对于做一些本身非常简单的事情来说,这听起来过于复杂:

  • 您有一个Post模型,其中包含通用属性(如作者和创建日期)
  • Post has_many :revisions
  • aRevision有一个reviewed布尔属性

如果您想查找 a 的最后审查修订Post,您可以:

class Post < ActiveRecord::Base
  has_many :revisions

  delegate :content, to: :current_revision # you can even have those to transparently delegate

  def current_revision
    @current_revision ||= revisions.where( reviewed: true ).order( "created_at desc" ).first
  end
end

如果您只想检索Post已审查修订的 s:

class Post < ActiveRecord::Base
  has_many :revisions

  scope :reviewed, ->{ group( 'posts.id' ) ).having( 'count(revisions.id) > 0' ).joins( :revisions ).where( "revisions.reviewed = ?", true ) }
end

这就是我的做法,让更熟悉的人paper_trail告诉你它的方式:)

编辑

正如评论中所讨论的,装饰器还可以帮助区分修订和委托方法,同时仍然能够传递活动记录关系。以这种方式给出一些东西:

class Post < ActiveRecord::Base
  has_many :revisions

  scope :reviewed, ->{ group( 'posts.id' ) ).having( 'count(revisions.id) > 0' ).joins( :revisions ).where( "revisions.reviewed = ?", true ) }

  def reviewed_revision
    @reviewed_revision ||= revisions.where( reviewed: true ).order( "created_at desc" ).first
  end

  def latest_revision
    @latest_revision ||= revisions.order( "created_at desc" ).first
  end
end

class PostDecorator
  attr_reader :post, :revision
  delegate :content, :updated_at, to: :revision

  def self.items( scope, revision_method )
    revision_method = :reviewed_revision unless %i[ reviewed_revision latest_revision ].include?( revision_method )

    scope.map do |post|
      PostDecorator.new( post, post.send( revision_method ) )
    end
  end

  def initalize( post, revision )
    @post, @revision = post, revision
  end

  def method_missing( action_name, *args, &block )
    post.send( action_name, *args, &block )
  end
end

# view
#
# <% PostDecorator.items( Post.reviewed.limit(10), :reviewed_revision ).each do |post| %>
# <p><%= post.author.name %></p>
# <p><%= simple_format post.content %></p>
# <% end %>
于 2016-07-31T16:12:41.187 回答