2009-09-01 35 views
1

说我有很多博客,并且每个博客都有has_many的帖子。这些存储在2个表格(“博客”和“帖子”)。是否可以将其他列(例如scoped_id)添加到存储由博客限定的ID的博客表中。Rails:范围ID除了主要ID

Blog: 1 
    - Posts 
    - id: 1, scoped_id: 1 
    - id: 2, scoped_id: 2 
    - id: 3, scoped_id: 3 
Blog: 2 
    - Posts 
    - id: 4, scoped_id: 1 
    - id: 5, scoped_id: 2 
    - id: 6, scoped_id: 3 

我知道counter_cache可以跟踪由家长博客作用域职位数。但是,如果帖子被销毁,我不希望scoped_id递减。

回答

1

你最好的选择是继续在博客上最后使用的ID,并通过填充它:

class Post < ActiveRecord::Base 
    … 
    before_create :populate_scoped_id 

    def populate_scoped_id 
    blog.increment!(:latest_scoped_post_id) 
    self[:scoped_id] = blog.latest_scoped_post_id 
    end 
    … 
end 

或一些爵士这样。

如果保存失败,计数器将不会增加,因为它全部在一个非常棒的事务中(它就像企业一样)。

+0

非常好。谢谢! – Homar

+0

当服务器同时处理两个请求时,这段代码容易受到竞争条件的影响,导致两个或多个博客条目具有相同的scoped_id。例如,请考虑以下顺序:(1)请求A读取latest_scoped_post_id x,(2)请求B读取相同的latest_scoped_post_id x,(3)请求A将scoped_id设置为x + 1,(4)请求B将scoped_id设置为x + 1(与请求A相同)。 – antinome

+0

你可能会认为在一个事务中保持这种竞争状态是可以避免的,但是它不会,除非你把事务隔离级别设置得非常高(可能是性能问题的一个坏主意)。 – antinome

1

是的,你绝对可以添加其他列,如果是我,我会做一个before_save回调保存scoped_id如果它是一个new_record?

class Post < ActiveRecord::Base 
    ... 
    before_save :populate_scoped_id 

    def populate_scoped_id 
    assign_the_scoped_id_method if self.new_record? 
    end 
    ... 
end 

希望它有助于=)

+0

谢谢,但你如何确保相同的scoped_id永远不会重复的父母的博客? – Homar

+1

我会采取最大的scoped_id并将其增加1(替换assign_the_scoped_id_method): self.scoped_id = Post.maximum(:scoped_id)+ 1 – Staelen

+3

不要忘记在数据库中添加唯一索引:add_index:posts,[ :id,:scoped_id],:unique => true。否则,可能(至少在理论上)是两个同时发生的请求,你最终可能会得到两次相同的scoped_id。 –