使用子类ActiveRecord模型使friendly_id范围更好

时间:2014-02-06 19:12:03

标签: ruby activerecord friendly-id

我有一个子类ActiveRecord模型,它使用一个单独的表来存储记录,而friendly_id(4.1.0.beta.1)则用于生成slug。问题是friendly_id正在使用父类的表来检查现有的slugs,而不是使用子表。基本上我希望friendly_id将其检查范围扩展到正确的表格。

示例:

class Parent
  friendly_id :name, :use => :slugged
end

class Child < Parent
  self.table_name = 'children'
end

Parent.create(name: 'hello').slug
> 'hello'

Child.create(name: 'hello').slug
> 'hello--2'

我希望friendly_id为第二次创建生成'hello'slug,因为子表中没有带有该slug的记录。有没有办法配置或使用类友好id用于其查询的补丁?

编辑:添加了friendly_id版本以供将来参考

1 个答案:

答案 0 :(得分:1)

我发布了自己的解决方案,以防万一有人遇到同样的问题。我应该重申,这个问题是在4.1.0.beta.1 gem的版本friendly_id上找到的(当时是最新版本),所以这个问题可能不再发生了。

为了解决这个问题,我基本上将slug_generator_class配置为使用我自己的类,所以我可以修补罪魁祸首方法。

在我的模型中:

friendly_id do |config|
  config.slug_generator_class = SubclassScopableSlugGenerator
end

在初始化程序中,我覆盖了FriendlyId::SlugGenerator.conflicts方法,因此我可以访问sluggable_class var:

# Lets a non-STI subclass of a FriendlyId parent (i.e. a subclass with its
# own dedicated table) have independent slug uniqueness.
class SubclassScopableSlugGenerator < FriendlyId::SlugGenerator
  private
  def conflicts
    # this is the only line we're actually changing
    sluggable_class = friendly_id_config.model_class

    pkey  = sluggable_class.primary_key
    value = sluggable.send pkey
    base = "#{column} = ? OR #{column} LIKE ?"
    # Awful hack for SQLite3, which does not pick up '\' as the escape character without this.
    base << "ESCAPE '\\'" if sluggable.connection.adapter_name =~ /sqlite/i
    scope = sluggable_class.unscoped.where(base, normalized, wildcard)
    scope = scope.where("#{pkey} <> ?", value) unless sluggable.new_record?

    length_command = "LENGTH"
    length_command = "LEN" if sluggable.connection.adapter_name =~ /sqlserver/i
    scope = scope.order("#{length_command}(#{column}) DESC, #{column} DESC")
  end
end