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