我有Post
和Comments
表。
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,也很棒。
答案 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
假设:如果允许删除遗嘱,评论书签可能会改变。