3

Using the Rails gem "friendly_id", is it possible to get a "live preview" of the slug to be created? Before the object is saved, that is (and to be returned while typing using an ajax request)?

If so, how?

TomDogg
  • 3,803
  • 5
  • 33
  • 60

2 Answers2

9

FriendyId author here.

FriendlyId internally uses the private set_slug to do this. This method is invoked via a before_validation callback. If for some reason you do not wish to call valid?, you can invoke the set_slug method via send, or define a method in your model which invokes it:

instance = ModelClass.new
instance.send(:set_slug)

# or
class ModelClass < ActiveRecord::Base
  friendly_id :name, use: :slugged

  def generate_slug_preview
    set_slug
  end
end 

However, note that bypassing or ignoring validations is often a bad idea. For example, if your model included a validation on the name field, and then you used that field as the basis of the slug, then you are previewing a slug that will never actually be generated.

Norman Clarke
  • 436
  • 2
  • 4
1

Per https://github.com/norman/friendly_id/blob/master/test/slugged_test.rb ...

  m1 = model_class.new :name => "a b c d"
  m1.valid?
  assert_equal "a-b-c-d", m1.slug

Looks like it's just .slug. Per other tests, you don't need the create - a new will do. So your strategy is:

  • add an onchange handler to the text field
  • each time the user changes it, use Ajax to send the current value to the server
  • new an instance of your model, with the name or whatever set to the value Ajax sent
  • call slug, and send the result back to the web page
  • display it in the web page

All that is standard Ajax stuff, with nothing to do with friendly_id. But it all makes me wonder if - because you show the slug to the user - friendly_id will let you then edit the slug, the way high-end blogs do.

And you probably must call valid? first.

Phlip
  • 5,253
  • 5
  • 32
  • 48
  • Thanks - unfortunately, calling something like ```Article.new(title: "A new article").slug``` returns nil... – TomDogg Dec 09 '13 at 22:29
  • Your solution is correct (it returned nil b/c my model has validations which failed b/c I only passed it the one value for the attribute needed for the generation of the slug). So, I'll have to make all validations conditional, i.e. ```validates :name, unless: :on_the_fly``` and then add to the model ```attr_accessor :on_the_fly``` and sumit a ```true``` value for it, each time the user ajax-submits their value-to-be-slugged. (On the other hand, this doesn't seem safe since it allows anyone to bypass validation.) – TomDogg Dec 09 '13 at 23:10
  • Tx but that solution sucks. Rails validations suck because validations belong on a Form, not on a Model. (Different users, seeing different forms, could experience different validations, for example.) So friendly_id should not require the .valid? call to pass just to generate a slug. – Phlip Dec 09 '13 at 23:14
  • Calling `Article.new(title: "A new article").slug` returns nil because you didn't invoke `valid?`, so the slug was never generated. Validations are actually important to the slug generation because in many cases the input into the slugging method comes from a field with validations, so it absolutely should be a part of the validation process. You can work around that as I described in my answer here, in the event you're generating a slug from input that doesn't have any validations associated with it. – Norman Clarke Dec 10 '13 at 14:27
  • Point. I should have more carefully detached why Rails validations suck from why friendly_id needs them. – Phlip Dec 10 '13 at 15:09