friendly_id: Breaks validates uniqueness: true

This seems to be the same issue as reported in the closed issue #152

My Gem file:

ruby '2.2.0'
gem 'rails', '4.2.0'
gem 'friendly_id', '~> 5.1.0'

Here is my model code:

validates :title, presence: true, uniqueness: true
  extend FriendlyId
  friendly_id :title, :use => :slugged

The

presence: true

validation works well, but my app does not apply the uniqueness validation… it will happily make model instances with duplicate :titles.

Elsewhere in my app, in models where I am not using Friendly_ID, I find the uniqueness validations work well.

Also – the slugging behavior and other features of Friendly_id do work as advertised.

thanks

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Reactions: 4
  • Comments: 16 (1 by maintainers)

Most upvoted comments

Hey @norman, I’m building a simple rails api with basic token authentication and authorization with the pundit gem. I’m using your gem for friendly urls but I’m running into this same issue. Here’s the code. I can’t link to the repo because it’s private but I’m not giving anything away here.

config/initializers/friendly_id.rb

# FriendlyId Global Configuration
FriendlyId.defaults do |config|
  # ## Reserved Words
  config.use :reserved

  config.reserved_words = %w(new edit index session login logout users admin
    stylesheets assets javascripts images)

  #  ## Friendly Finders

  config.use :finders

  # ## Slugs

  config.use :slugged

  #  ## Tips and Tricks
  #
  #  ### Controlling when slugs are generated

  config.use Module.new {
    def should_generate_new_friendly_id?
      friendly_slug_method = method(friendly_id_config.base)
      did_it_change = method(friendly_slug_method.call[0].to_s + "_changed?")
      slug.blank? || did_it_change.call
    end

    def default_candidates  # Added default candidates for use with slugged.
      [
        :name,
        [:name, :id]
      ]
    end
  }

end

I’m building the methods instead of sending them because I read somewhere it’s faster??? Who knows, but it works for what I’m doin? The default_candidates just allows me to dry up my models a bit since in this particular app they all have a similar structure.

client.rb

class Client < ActiveRecord::Base
  include Tokenable

  extend FriendlyId # Be sure to check out the initializer for defaults.
  friendly_id :default_candidates

  after_initialize :set_default_role, if: :new_record?

  validates :auth_token, uniqueness: true
  validates :name, uniqueness: true, presence: true
  validates :slug, uniqueness: true, presence: true

  enum role: [:client, :admin]

  private

  def set_default_role
    self.role ||= :client
  end

end

RSpec model_spec.rb

describe Client, type: :model do
  before { @client = create :client }
  subject { @client }

  it { should be_valid }

  it { should respond_to(:name) }
  it { should validate_presence_of(:name) }
  it { should validate_uniqueness_of(:name) }

  it { should respond_to(:slug) }
  it { should validate_presence_of(:slug) }
  it { should validate_uniqueness_of(:slug) }

  it { should respond_to(:auth_token) }
  it { should validate_uniqueness_of(:auth_token) }

end

Failure Message

rspec spec/models/client_spec.rb
.....F...

Failures:

  1) Client should require slug to be set
     Failure/Error: it { should validate_presence_of(:slug) }
       Expected errors to include "can't be blank" when slug is set to nil,
       got no errors
     # ./spec/models/client_spec.rb:12:in `block (2 levels) in <top (required)>'
     # ./spec/support/database_cleaner.rb:9:in `block (3 levels) in <top (required)>'
     # /austinerlandson.rvm/gems/ruby-2.2.2/gems/database_cleaner-1.5.0/lib/database_cleaner/generic/base.rb:16:in `cleaning'
     # /austinerlandson.rvm/gems/ruby-2.2.2/gems/database_cleaner-1.5.0/lib/database_cleaner/base.rb:92:in `cleaning'
     # /austinerlandson.rvm/gems/ruby-2.2.2/gems/database_cleaner-1.5.0/lib/database_cleaner/configuration.rb:86:in `block (2 levels) in cleaning'
     # /austinerlandson.rvm/gems/ruby-2.2.2/gems/database_cleaner-1.5.0/lib/database_cleaner/configuration.rb:87:in `call'
     # /austinerlandson.rvm/gems/ruby-2.2.2/gems/database_cleaner-1.5.0/lib/database_cleaner/configuration.rb:87:in `cleaning'
     # ./spec/support/database_cleaner.rb:8:in `block (2 levels) in <top (required)>'

Finished in 0.33867 seconds (files took 2.68 seconds to load)
9 examples, 1 failure

Failed examples:

rspec ./spec/models/client_spec.rb:12 # Client should require slug to be set

it fails because, from what I’ve read from your previous versions, slug generation happens on a before validation callback. But shouldn’t that mean that the validation spec’s should be working? Looking at the stack trace I’m thinking it’s an issue with databasecleaner maybe but it’s hard to tell? Adding pry calls or byebugs to shoulda-matchers to poke around is usually time consuming in these cases.

My uniqueness test is passing which I know is slightly different from what’s happening in the title.

All this said, is it even relevant to be testing the slug column given that the gem is being tested on it’s own? Meaning if the functionality is there and the plugin itself is vetted, isn’t testing that it’s working in my code similar to testing Devise?

I’m mainly asking because I’m wondering if I even need to test it?