Search code examples
ruby-on-railsrubypostgresqlspreefriendly-id

friendly_id slug not generating, but methods being called


I'm trying to add a friendly_id slug to an existing Rails model, Spree::Variant. Variant belongs_to Product, which already has its own slugs that are working fine (Spree and these models are from a 3rd party gem).

When I try saving a Variant I'm expecting a slug to be generated and saved to the slug field in the database, but the field remains NULL.

Here's my model code:

Spree::Variant.class_eval do
  extend FriendlyId
  friendly_id :slug_candidates, :use => :slugged
  validates :slug, length: { minimum: 3 }, allow_blank: true, uniqueness: true

  self.whitelisted_ransackable_attributes = %w[weight sku slug]

  def parent_slug
    self.product.slug
  end

  def option_value_list
    if !self.option_values.nil? && self.option_values.length > 0
      opts = self.option_values.collect{ |v| 
      v.presentation }.join('-')
      return opts
    else
      return ''
    end
  end

  def slug_candidates
    [
      [:parent_slug, :option_value_list],
      [:parent_slug, :option_value_list, :sku]
    ]
  end

  def should_generate_new_friendly_id?
    puts "Is new #{new_record?}, is blank #{slug.blank?}" #Is new false, is blank true when updating test record
    new_record? || slug.blank?
  end

end

Similar questions are answered with making sure should_generate_new_friendly_id? is defined correctly, which it appears to be here. I've verified that it gets called and return True when I update a record, yet the record still doesn't end up with a slug.

I've also verified that option_value_list is called, and outputs the desired information. An example return value from my app is "Titanium".

Why isn't my slug created? Where can I look to narrow the problem further?


Solution

  • I can't really say I know the solution, but to narrow down the problem, you need to check the Spree::Variant source code which delegates the slug to the product table.

    On the product table, the slug is a has_many relationship, known by the use: :history. (Not related to the problem)

    The problem is with the Spree::Core::DelegateBelongsTo#(delegator_for_setter|| delegator_for) methods, which are returning early if the column name exists on the table, rather than reading or updating the records accordingly.

    A way to work around these(as I don't know if Spree provides a better approach for handling these) are to redefine your slug methods as such:

    def slug
      read_attribute(:slug)
    end
    
    def slug=(new_slug)
      write_attribute(:slug, new_slug)
    end
    

    Hope I was able to help.