validates_uniqueness_of fails because (1) no index on subject, (2) sqlite3 problem or (3) other?

Hi,

I've got 5 validations on my model. Only one of them fails to perform
as expected:

class Portfolio < ActiveRecord::Base
  [snip]
  validates_uniqueness_of :symbol
end

I'm running Rails 2.0.2. I created the app following a couple of very
helpful Rails 2.0 newbie tutorials.

I got sqlite3 as the DBMS by default, which I don't know. To solve
this, I'm going to try:
1. Adding, using SQL, an index to the Symbol column of the portfolios
table in the development.sqlite3 database
2. Switching to MySQL 5.0, which I'm experience with, by regenerating
the app with rails -d

Any comments/observations/suggestions welcome.

Thanks in Advance,
Richard

RichardOnRails wrote:

Hi,

I've got 5 validations on my model. Only one of them fails to perform
as expected:

class Portfolio < ActiveRecord::Base
  [snip]
  validates_uniqueness_of :symbol
end

Hi Richard,

How is it failing? What are you expecting? What is it doing? Is there an
error message? What does the migration for portfolios look like?

I think we need a bit more information.

Peace,
Phillip

Hi Phillip,

Thanks for expressing an interest in my problem.

What does the migration for portfolios look like?

class CreatePortfolios < ActiveRecord::Migration
  def self.up
    create_table :portfolios do |t|
      t.string :symbol
      t.string :name

      t.timestamps
    end
  end

  def self.down
    drop_table :portfolios
  end
end

How is it failing? What is it doing?

I click on "New portfoilo", enter a three-letter Symbol "XXX" and
click "Create".
That yields the response "Portfolio was successfully created." and
displays the Symbol and Name (the latter being blank).
I click "Back" and see the new (XXX) Symbol and its (blank) Name
displayed, along with other pairs I've entered.

What are you expecting?

I repeat this process and see another instance of XXX. That' violates
the uniqueness declaration in the following specification:

class Portfolio < ActiveRecord::Base
  before_save :uppercase_data

  def uppercase_data
    self.symbol.upcase!
  end

  validates_presence_of :symbol
  validates_length_of :symbol, :maximum=>5, :message=>"exceeds %d
characters"
  validates_uniqueness_of :symbol
  validates_format_of :symbol, :with => /^[a-zA-Z\d]+$/, :on
=> :create,
    :message => "(Character other than letter or digit found, e.g a
blank)"
end

Is there an error message?

No. But there should be an error message indicating the the second
XXX could not be added because it's not unique.

Please let me know if there's anything else I can provide.

I'm going to get my personal website under my ISP's aegis re-
established so I can just post my code so that any interested party
can simply view whatever part he wishesl

Sincerely,
Richard

Hi Phillip,

False alarm. I entered the constraint using my favorite editor,
SciTE, and failed to save my change :-(. Mea culpa for putting you
(and me) to this trouble.

Best wishes,
Richard

RichardOnRails wrote:

Hi Phillip,

False alarm. I entered the constraint using my favorite editor,
SciTE, and failed to save my change :-(. Mea culpa for putting you
(and me) to this trouble.

Best wishes,
Richard

On Jun 23, 4:23 pm, Phillip Koebbe <rails-mailing-l...@andreas-s.net>

Richard,

That's okay. I got a good laugh out of it, so it's worth something!

Peace,
Phillip

Hi Phillip,

I got a good laugh out of it, so it's worth something!

OK, here’s an opportunity to pay for the humor I provide :slight_smile:

Presently, I report as an error user input for Symbol containing a
non-letter or non-digit. I’d like to relax that in the case where the
offending characters are merely leading and/or trailing whitespace.

I plan to accomplish this by preceding the constraint:
  validates_format_of :symbol, :with => /^[a-zA-Z\d]+$/, :on
=> :create,
    :message => "(Character other than letter or digit found, e.g a
blank)"
with the following:
  parameters[:symbol] =~ /^\s*([A-Za-z0-9])\s*$/
  parameters[:symbol] = $1 if $1

I haven’t tried it yet, but I’m a pessimist. If it works, I’ll send
you another “false alarm” mea culpa.
On the other hand, if you see an error or a more Rails-y way to do
this, I’d appreciate hearing from you.

Best wishes,
Richard

RichardOnRails wrote:

offending characters are merely leading and/or trailing whitespace.

This is similar to the uppercase problem: why raise an error when you
can just do it yourself? Instead of raising an error and telling the
user to not use whitespace at the beginning or end of the symbol, why
not just get rid of it yourself?

" a string with leading and trailing spaces ".strip =>
"a string with leading and trailing spaces"

Beyond that, I'm not at all qualified to give any kind of suggestions
when it comes to regular expressions. I have looked at them a few
times, and have even read some decent tutorial material, but since I
don't use them very often, it all goes away very quickly. Just like
physics when I was in college.

Peace,
Phillip

Hi Phillip,

This is similar to the uppercase problem: why raise an error when you
can just do it yourself?

That's precisely what I'm trying to do, i.e strip leading/trailing
spaces silently. I've already realized my code is in error by
referring to 'parameters' rather than 'params'.

I'm fine with the RE stuff. In case you're interested, I'll explain
what the code does and provide a small Ruby program to demo it.

If you're not interested about Ruby regex's, READ NO FURTHER and
accept my thanks for your willingness to look ino my problem. BTW, I
just posted a question about my "params" stumbling block.

Best wishes,
Richard

The expression /^\s*([A-Za-z0-9])+\s*$/ says:
^ Start scanning at the beginning
\s match any "whitespace" character, e.g. space, tab, etc.
\s* match zero or as many as possible (with some caveats) whitespace
characters
() match the specification within the parentheses and assign $1 a
reference to the matching value
[A-Za-z0-9] matches any of the characters A to Z, a to z and 0 to 9,
i.e. any of these 62 characters
A-Za-z0-9]+ matches one or more of the such characters, as many as
possible, with some caveats

So when params[:symbol] (containing the data the user supplied in the
textbox labelled Symbol) matches this pattern, then $1 contains the
string of legitimate character surrounded front and back by zero or
more whitespace characters. If for example, the params[:symbol]
contained " AB CD ", this string would NOT match the pattern, so $1
would me nil and my algorithm would leave params unchanged, and the
subsequent constraint would flag the entry as invalid.

But if the parms[:symbol] contained " ABCD ", that string would be
replaced with "ABCD" and the subsequent constraint would be
satisfied.

Here's a Ruby example:

RichardOnRails wrote:

Hi Phillip,

That's precisely what I'm trying to do, i.e strip leading/trailing
spaces silently.

Have you looked into String#gsub? You can feed it a regex for the
pattern, so you should be able to easily take out all characters that
aren't in the 62 acceptable ones.

http://www.ruby-doc.org/core-1.8.6/index.html

Peace,
Phillip

Hi Phillip,

I just noticed this addition suggestion made last week.

I did know about String#gsub but opted in this application not to
automatically eliminate embedded blanks (versus leading and trailing
blanks). I regard embedded blanks as likely indicative of some other
user error beyond the blank itself.

Nevertheless, I appreciate your pointing out something else I might
be unaware of.

Best wishes,
Richard