根据关联重置PK号

时间:2014-05-29 20:16:19

标签: ruby-on-rails ruby sequel

我有PostComments表。

Post有很多评论,Comment属于帖子。

当我为Post创建注释时,我希望主键从1开始,以便我可以以REST-ful的方式访问注释,例如:

/posts/1/comments/1
/posts/1/comments/2
/posts/2/comments/1
/posts/2/comments/2

如何使用Rails 3实现这一目标? 我使用MySQL作为数据库。

奖励:我正在使用Sequel ORM;与Sequel兼容的方法,不仅仅是ActiveRecord,也很棒。

2 个答案:

答案 0 :(得分:3)

好吧,你不能使用id,因为id是主键。你可以做的是在你的数据库表中添加一个额外的字段,如comment_number,并使其在帖子的范围内是唯一的:

#migration
def change
  add_column :comments, :comment_number, :integer, null: false
  add_index :comments, [:post_id, :comment_number], unique: true
end

#Class
class Comment < ActiveRecord::Base
  belongs_to :post

  validates :post_id, presence: true
  validates :comment_number, uniqueness: { scope: :post_id } 
end

现在有了这个,您需要确保填充此列:

class Comment < ActiveRecord::Base
  #...

  before_create :assign_comment_number

  private

  def assign_comment_number
    self.comment_number = (self.class.max(:comment_number) || 0) + 1
  end 
end

最后一步是告诉rails使用此列而不是id。为此,您需要覆盖to_param方法:

class Comment < ActiveRecord::Base
  #...
  def to_param
    comment_number
  end
end

更新

还有一件事,将此字段设为只读是非常有用的:

class Comment < ActiveRecord::Base
  attr_readonly :comment_id
end

此外,在重新考虑comment_number上进行唯一性验证之后,如果在运行验证后分配了它,则无意义。最有可能你应该摆脱它并依赖数据库索引。

即使进行了此验证,仍然存在可能的情况竞争。我可能会重写save方法来处理约束验证异常,重试几次以确保这不会破坏应用程序流。但这是另一个问题的主题。

答案 1 :(得分:1)

另一种不改变模型的选择:

get 'posts/:id/comments/:comment_id', to: 'posts#get_comment'

在帖子控制器中:

def get_comment
  @comment = post.find(params[:id]).comments[params[:comment_id] -1]
end

假设:如果允许删除遗嘱,评论书签可能会改变。