How to generate calculated db fields

I’m trying to generate a “page slug” i.e. a url sanitized id from
some text in my model that I want to be saved into the database and
I’m not seeing how I can do it.

The closest I’ve come to getting this to work has been…

class Page < ActiveRecord::Base
attr :name

before_save :generate_slug

def generate_slug
self.slug = self.name.gsub /\W+/, ‘-’
end
end

…but this is unsatisfactory as I would like to have the slug
generated from the name without having to save to the database.

anyone have an idea of the proper Ruby way? Ideally I’d like to be
able to do the following…

p = Page.new :name => ‘My test page’
=> #<Page:0x271ff38 @attributes={“slug”=>“My-test-page”, “name”=>“My
test page”}, @new_record=true>
p.slug
=> “My-test-page”
p.name = ‘Foo B.’
=> “Foo B.”
p.slug
=> “Foo-Bar”

Ideally it seems that Page#slug should generate the slug based on the
name every time it is accessed like

def slug
self.name.gsub /\W+/, ‘-’
end

but it seems when I save my model to the db Page#slug does not get
called and so the slug does not get saved to the db (and therfore
remains ‘null’). Any ideas? TIA


Craig B.

http://www.luckybonza.com
AIM: kreiggers

In reply to my own post…

def generate_slug
self.slug = self.name.gsub /\W+/, ‘-’
end
end

…but this is unsatisfactory as I would like to have the slug
generated from the name without having to save to the database.

a couple of other constriants…

  1. the slug should be write only as it is calculated from the
    Page#name so should only change when the name does
  2. the slug has to be stored in the db as this is how I’m going to
    retrieve the record

p.slug
called and so the slug does not get saved to the db (and therfore
remains ‘null’). Any ideas? TIA


Craig B.

http://www.luckybonza.com
AIM: kreiggers

Craig B. wrote:

I’m trying to generate a “page slug” i.e. a url sanitized id from
some text in my model that I want to be saved into the database and
I’m not seeing how I can do it.

The closest I’ve come to getting this to work has been…

class Page < ActiveRecord::Base
attr :name

before_save :generate_slug

def generate_slug
self.slug = self.name.gsub /\W+/, ‘-’
end
end

…but this is unsatisfactory as I would like to have the slug
generated from the name without having to save to the database.

anyone have an idea of the proper Ruby way? Ideally I’d like to be
able to do the following…

p = Page.new :name => ‘My test page’
=> #<Page:0x271ff38 @attributes={“slug”=>“My-test-page”, “name”=>“My
test page”}, @new_record=true>
p.slug
=> “My-test-page”
p.name = ‘Foo B.’
=> “Foo B.”
p.slug
=> “Foo-Bar”

Ideally it seems that Page#slug should generate the slug based on the
name every time it is accessed like

def slug
self.name.gsub /\W+/, ‘-’
end

but it seems when I save my model to the db Page#slug does not get
called and so the slug does not get saved to the db (and therfore
remains ‘null’). Any ideas? TIA

Combine your before_save callback with lazy initialization in the
accessor.

before_save :slug

def slug
@slug ||= self.name.gsub /\W+/, ‘-’
end

def name=(name)
attributes[:name] = name
slug = nil
end

By the way, here’s the snippet I use for slugs. It’s a bit more
forgiving of odd user input than yours. (based on Rick O.'s in
Mephisto, then tweaked all to heck)

title.downcase.gsub(/['"]/, ‘’).gsub(/\W+/, ’ ‘).squeeze(’
').strip.gsub(/ /, ‘-’)


Josh S.
http://blog.hasmanythrough.com