Search code examples
ruby-on-rails-3activerecordvirtual-attribute

How to get ActiveRecord record by virtual attribute?


In Rails 3, how can I retrieve a record by looking up on a virtual attribute? I have a name column and a slug that does a simple modification to it (see code below). How can I do a "reverse lookup" by slug to name?

I'm trying to find the right code for the find_by_slug method below:

class Brand < ActiveRecord::Base
  has_many :sale_items
  validates :name, :uniqueness => true

  def slug
    self.name.downcase.gsub(/\s/, '-')
  end

  def self.find_by_slug(given_slug)
    first(slug: given_slug)
  end
end

When I try find_by_slug in the Rails console I'm given an Unknown key: slug error.

This question seems similar but I'm not sure if it's the same as my problem. I'd appreciate some insight and help!


Solution

  • Since slug doesn't exist in the database you can't query for it with first. What you need to do is search on the name. But in order to do that, your 'name to slug' mapping needs to be reversible. You need to be able to do

    name = 'San Francisco'
    slug = convert_to_slug(name)  #san-francisco
    name == convert_to_name(slug) #true
    

    So that given a slug, you know what it's name would be - you can then do find_by_name. Right now your slug conversion

    downcase.gsub(/\s/, '-')
    

    is not reversible, unless there's some implicit information that you're not sharing with us, like 'there are only spaces and every first letter is capitalized'. So it can't be done, and you're best off making this a regular attribute and not a virtual one. If your conversion is reversible, then you just have to use

    find_by_name(convert_to_name(slug))