Can't access params in my model class

Hi All,

I've got a set of constraints in my model that work fine. I wanted to
remove leading and trailing blanks in a :symbol entry if it is
otherwise valid. So I added lines 9 & 10, as seen in the model class
below. BTW, I tested those lines in a simple Ruby program (after
declaring params = Hash.new) and theY worked fine for my purposes.

With the addition of lines 9 & 10, Rails reports:
undefined local variable or method `params'
and subsequently identifies line 10 as the offender.

I think I'm supposed to get the pamams from the session object. How
can I do that in Rails 2.0.2?

I'm running Ruby 1.8.6 and Rails 2.0.2 over WinXP-Pro/SP2.

Thanks in advance,
Richard

class Portfolio < ActiveRecord::Base
  before_save :uppercase_data

  def uppercase_data
    self.symbol.upcase!
  end

  validates_presence_of :symbol

  params[:symbol] =~ /^\s*([A-Za-z0-9]*)\s*$/ # Line 10
  params[:symbol] = $1 if $1 # Line 11

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

You can't access the params in a model, only in controllers.
You must assign the param to a model attribute and then validate that.
Since you already have symbol, you can simply do a

Portfolio.new(:symbol => params[:symbol])

in the controller

Hi Thorsten,

Thanks for responding to another of my dumb questions :slight_smile:

I adapted you rsuggestion to my situation, as shown below in the “new”
method of the
“class PortfoliosController < ApplicationController” definition:

  def new
    @portfolio = Portfolio.new # 1
    debugger # RLM 8/22/08 # 2
    Portfolio.new(:symbol => params[:symbol]) # 3
    :symbol=~ /^\s*([A-Za-z0-9]*)\s*$/ # 4
    Portfolio.new(:symbol => params[:symbol] = $1 if $1) # 5

    respond_to do |format|
      format.html # new.html.erb
      format.xml { render :xml => @portfolio }
    end
  end

Line 3 appears to be fine. At least I got no error regarding it when
I ran my app.
Line 4 works correctly in a Ruby app (shown below) that tests my
editing scheme. Ditto: no error in this run.
Line 5 yields a syntax error message from Rails:

K:/_Projects/Ruby/_Rails_Apps/AIMS_1/app/controllers/
portfolios_controller.rb:31: syntax error, unexpected kIF_MOD,
expecting ')'
    Portfolio.new(:symbol => params[:symbol] = $1 if $1) # 5

I tried a few variations on #5 to get :string to refer to data ($1)
extracted from the data originally referenced by string.

Question 1: Can statement #5 be made repaired both in terms of syntax
and semantics?
Question 2. Do statements #3 and 4 look semantically correct?
Question 3. Do you have the time to explain or point to an on-
reference that account for the fact that:
    “Portfolio.new(:symbol => params[:symbol])” is correct syntax,
while
    “:symbol => params[:symbol]” gets flagged as a syntax error

Again, thank you in advance for any help/guidance you may offer this
humble Rails newbie.

Best wishes,
Richard

P.S. Ruby app testing editing scheme
# Strip leading and trailing blanks
# if they surround a string of mere letters and/or digits
DATA.each { |line|
  params = Hash.new
  params[:symbol] = line.chomp
  params[:symbol] =~ /^\s*([A-Za-z0-9]+)\s*$/
  params[:symbol] = $1 if $1
  printf("\"%s\" matches %s
    params[:symbol] = \"%s\"\n", line.chomp,
    ($1 ? $1 : 'nil'),
    params[:symbol])
}

__END__
ABCD
  DE CD
  DEXCD

Line 5 yields a syntax error message from Rails:

K:/_Projects/Ruby/_Rails_Apps/AIMS_1/app/controllers/
portfolios_controller.rb:31: syntax error, unexpected kIF_MOD,
expecting ')'
   Portfolio.new(:symbol => params[:symbol] = $1 if $1) # 5

I tried a few variations on #5 to get :string to refer to data ($1)
extracted from the data originally referenced by string.

Question 1: Can statement #5 be made repaired both in terms of syntax
and semantics?

You can't have a statement modifier inside a function call like that.

Question 2. Do statements #3 and 4 look semantically correct?

4 looks like nonsense since it won't ever set $1. You need to be matching against params[:symbol], not :symbol.

Question 3. Do you have the time to explain or point to an on-
reference that account for the fact that:
   “Portfolio.new(:symbol => params[:symbol])” is correct syntax,
while
   “:symbol => params[:symbol]” gets flagged as a syntax error

It's only legal to elide the braces surrounding a hash when it's the last parameter to a method.

Fred

RichardOnRails wrote:

Hi Thorsten,

Thanks for responding to another of my dumb questions :slight_smile:

I adapted you rsuggestion to my situation, as shown below in the �new�
method of the
�class PortfoliosController < ApplicationController� definition:

  def new
    @portfolio = Portfolio.new # 1
    debugger # RLM 8/22/08 # 2
    Portfolio.new(:symbol => params[:symbol]) # 3
    :symbol=~ /^\s*([A-Za-z0-9]*)\s*$/ # 4
    Portfolio.new(:symbol => params[:symbol] = $1 if $1) # 5

    respond_to do |format|
      format.html # new.html.erb
      format.xml { render :xml => @portfolio }
    end
  end

Hi again, Richard

I think you have misunderstood what Thorsten meant by the Portfolio.new
statement. When you create objects based on ActiveRecord models, you
can do so in a couple of ways. Suppose I have a User model with
first_name and last_name attributes, I could do

user = User.new
user.first_name = 'Some'
user.last_name = 'Guy'
user.save

or I could

user = User.new({:first_name => 'Some', :last_name => 'Guy'})
user.save

or even

user = User.create({:first_name => 'Some', :last_name => 'Guy'})
# create does the save for you, no need to call it explicitly

oh, and there's

user = User.new
user.update_attributes(params[:user])

which assumes that there are params[:user][:first_name] and
params[:user][:last_name] like you would get when using a form_for.

When you validate user input, you do so in the object, the actual
instance of the model. All of the models validations run against the
instance data. Maybe it will help if you knew that you can do this:

user = User.new
user.valid?

If you have validations in place, you're going to get false. It seems
that what you want to do is something like this:

# create a portfolio object
# set the attributes to the user's input
# either try to save it or just run the validations, if they fail,
return the user to the edit screen

portfolio = Portfolio.new{:symbol => params[:symbol], :name =>
params[:name])
if portfolio.save
    # do one thing
else
    # do something else
end

Peace,
Phillip

Hey Frederick and Phillip,

Thanks a lot for weighing in with your great explanations and
suggestions. I tried putting my editing code in the controller’s new
method, but that was ineffective.. So I thought about it some more.

It seems like the removing-leading/following blanks can’t be done in
the contoller, because no user data has been entered yet.

The model class seems like the perfect place to make a change, so I
modified portfolio.rb, as shown below. The good news is that no error
messages are reported. The bad news is that it doesn’t remove blanks,
as I intend. But there ought to be some way to modify the model
instance before the validations are applied.

Any new ideas, guys? Again, thanks for your responses. I’m going to
study them some more to see if there’s a nugget I missed.

Best wishes,
Richard

class Portfolio < ActiveRecord::Base
  before_save :uppercase_data

  def uppercase_data
    self.symbol.upcase!
  end

  # Remove leading/trailing blanks, if any # 1
  sym = params[:portfolio][:symbol] # 2
  sym =~ /^\s*([A-Za-z0-9]+)\s*$/ # 3
  params[:portfolio][:symbol] = $1 if $1 # 4

  validates_presence_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)"
  validates_length_of :symbol, :maximum=>5, :message=>"exceeds %d
characters"
  validates_uniqueness_of :symbol
end

Hey Frederick and Phillip,

Thanks a lot for weighing in with your great explanations and
suggestions. I tried putting my editing code in the controller’s new
method, but that was ineffective.. So I thought about it some more.

It seems like the removing-leading/following blanks can’t be done in
the contoller, because no user data has been entered yet.

The model class seems like the perfect place to make a change, so I
modified portfolio.rb, as shown below. The good news is that no error
messages are reported. The bad news is that it doesn’t remove blanks,
as I intend. But there ought to be some way to modify the model
instance before the validations are applied.

Any new ideas, guys? Again, thanks for your responses. I’m going to
study them some more to see if there’s a nugget I missed.

Best wishes,
Richard

class Portfolio < ActiveRecord::Base
  before_save :uppercase_data

  def uppercase_data
    self.symbol.upcase!
  end

  # Remove leading/trailing blanks, if any # 1
  sym = params[:portfolio][:symbol] # 2
  sym =~ /^\s*([A-Za-z0-9]+)\s*$/ # 3
  params[:portfolio][:symbol] = $1 if $1 # 4

  validates_presence_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)"
  validates_length_of :symbol, :maximum=>5, :message=>"exceeds %d
characters"
  validates_uniqueness_of :symbol
end

RichardOnRails wrote:

Hey Frederick and Phillip,

Thanks a lot for weighing in with your great explanations and
suggestions. I tried putting my editing code in the controller�s new
method, but that was ineffective.. So I thought about it some more.

Right. The new action is for preparing any data you need to present a
form to the user. The form posts back to either create or update (if
you're using a RESTful approach), and in that action you have to start
by creating a portfolio object. So if this is a new portfolio, you
should have code similar to

def create
    portofolio = Portfolio.new({:symbol => params[:symbol])
    if portfolio.save
        # do the success stuff here
    else
        # do the failure stuff here
    end
end

Then in your Portfolio model, you could have

def before_validation
    self.symbol.gsub!(<put your regex here>, '')
end

or possibly

def before_validation_on_create
end

So the symbol attribute will get the white spaces stripped out before
the validations run.

It seems like the removing-leading/following blanks can�t be done in
the contoller, because no user data has been entered yet.

It can, but not in the new action as explained above. It's a process
that should be in the model, though, as it relates specifically to the
business logic of the data.

Peace,
Phillip

Hi Phillip,

I've got pro-active validation working perfectly for my purposes. I
thought I posted a Thank You about that hours ago, but I don't see
that msg listed on this thread. So I'll repeat myself. Thank you for
hanging in there with me until I actually got this thing working
properly. Aside from the usefully of this validation routine to my
nascent application, I learned a lot about Rails 2.0.

Thank you, again. The final code is posted below.

Best wishes,
Richard

class Portfolio < ActiveRecord::Base
  def before_validation
    # Remove leading/trailing blanks, if any
    self.symbol =~ /^(\s*)(.*?)(\s*)$/
    self.symbol = $2 if $1 or $3
    # Upshift before following validations are applied
    self.symbol.upcase!
  end

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