Creating new object using params posted from form


#1

Hi,

I have a problem creating an new instance of an object using params
posted
from a form.

The object being created is not a sub class of ActiveRecord and is very
simple. It’s model file is just:

class Search

attr_accessor :major_build_id, :minor_build_id, :environment_id,
:system_id

end

The controller creates an empty instance variable the first time the
page is
called, else it tries to populate it with the values of params from the
form.

class ResultsController < ApplicationController

def index
list
render :action => ‘list’
end

def list
if request.get?
@search = Search.new
else
@search = Search.new(params[:search])
end
end

end

The form on the results/index page which populates the form posts back
to
itself and is also very simple

<%= start_form_tag %>

Major Build Name<%= select :search, :major_build_id, [["Select", ""]]+@major_builds %>
Minor Build Name<%= select :search, :minor_build_id, [["Select", ""]]+@minor_builds %>
Environment<%= select :search, :environment_id, [["Select", ""]]+@environments %>
System<%= select :search, :system_id, [["Select", ""]]+@systems %>
<%= submit_tag 'Update Results' %>

<%= end_form_tag %>

The first time I call the page (using the GET request) is fine, but if I
use
the form to post any data I get an error.

ArgumentError in Results#index

wrong number of arguments (1 for 0)

RAILS_ROOT: ./script/…/config/…
Application Trace <#> | Framework Trace <#> | Full Trace <#>

#{RAILS_ROOT}/app/controllers/results_controller.rb:13:in initialize' #{RAILS_ROOT}/app/controllers/results_controller.rb:13:innew’
#{RAILS_ROOT}/app/controllers/results_controller.rb:13:in list' #{RAILS_ROOT}/app/controllers/results_controller.rb:4:inindex’
-e:3:in `load’
-e:3

c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/base.rb:853:in
send' c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/base.rb:853:inperform_action_without_filters’
c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/filters.rb:332:in
perform_action_without_benchmark' c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/benchmarking.rb:69:inperform_action_without_rescue’
c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/benchmarking.rb:69:in
measure' c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/benchmarking.rb:69:inperform_action_without_rescue’
c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/rescue.rb:82:in
perform_action' c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/base.rb:369:insend’
c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/base.rb:369:in
process_without_session_management_support' c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/session_management.rb:116:inprocess’
c:/ruby/lib/ruby/gems/1.8/gems/rails-1.0.0/lib/dispatcher.rb:38:in
dispatch' c:/ruby/lib/ruby/gems/1.8/gems/rails-1.0.0/lib/webrick_server.rb:117:inhandle_dispatch’
c:/ruby/lib/ruby/gems/1.8/gems/rails-1.0.0/lib/webrick_server.rb:83:in
service' c:/ruby/lib/ruby/1.8/webrick/httpserver.rb:104:inservice’
c:/ruby/lib/ruby/1.8/webrick/httpserver.rb:65:in run' c:/ruby/lib/ruby/1.8/webrick/server.rb:155:instart_thread’
c:/ruby/lib/ruby/1.8/webrick/server.rb:144:in start' c:/ruby/lib/ruby/1.8/webrick/server.rb:144:instart_thread’
c:/ruby/lib/ruby/1.8/webrick/server.rb:94:in start' c:/ruby/lib/ruby/1.8/webrick/server.rb:89:ineach’
c:/ruby/lib/ruby/1.8/webrick/server.rb:89:in start' c:/ruby/lib/ruby/1.8/webrick/server.rb:79:instart’
c:/ruby/lib/ruby/1.8/webrick/server.rb:79:in start' c:/ruby/lib/ruby/gems/1.8/gems/rails-1.0.0/lib/webrick_server.rb:69:indispatch’
c:/ruby/lib/ruby/gems/1.8/gems/rails-1.0.0/lib/commands/servers/webrick.rb:59
c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:18:in
require__' c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:18:inrequire’
c:/ruby/lib/ruby/gems/1.8/gems/activesupport-1.2.5/lib/active_support/dependencies.rb:214:in
require' c:/ruby/lib/ruby/gems/1.8/gems/rails-1.0.0/lib/commands/server.rb:28 c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:18:inrequire__’
c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:18:in
require' c:/ruby/lib/ruby/gems/1.8/gems/activesupport-1.2.5/lib/active_support/dependencies.rb:214:inrequire’
./script/server:3

#{RAILS_ROOT}/app/controllers/results_controller.rb:13:in initialize' #{RAILS_ROOT}/app/controllers/results_controller.rb:13:innew’
#{RAILS_ROOT}/app/controllers/results_controller.rb:13:in list' #{RAILS_ROOT}/app/controllers/results_controller.rb:4:inindex’
c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/base.rb:853:in
send' c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/base.rb:853:inperform_action_without_filters’
c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/filters.rb:332:in
perform_action_without_benchmark' c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/benchmarking.rb:69:inperform_action_without_rescue’
c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/benchmarking.rb:69:in
measure' c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/benchmarking.rb:69:inperform_action_without_rescue’
c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/rescue.rb:82:in
perform_action' c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/base.rb:369:insend’
c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/base.rb:369:in
process_without_session_management_support' c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/session_management.rb:116:inprocess’
c:/ruby/lib/ruby/gems/1.8/gems/rails-1.0.0/lib/dispatcher.rb:38:in
dispatch' c:/ruby/lib/ruby/gems/1.8/gems/rails-1.0.0/lib/webrick_server.rb:117:inhandle_dispatch’
c:/ruby/lib/ruby/gems/1.8/gems/rails-1.0.0/lib/webrick_server.rb:83:in
service' c:/ruby/lib/ruby/1.8/webrick/httpserver.rb:104:inservice’
c:/ruby/lib/ruby/1.8/webrick/httpserver.rb:65:in run' c:/ruby/lib/ruby/1.8/webrick/server.rb:155:instart_thread’
c:/ruby/lib/ruby/1.8/webrick/server.rb:144:in start' c:/ruby/lib/ruby/1.8/webrick/server.rb:144:instart_thread’
c:/ruby/lib/ruby/1.8/webrick/server.rb:94:in start' c:/ruby/lib/ruby/1.8/webrick/server.rb:89:ineach’
c:/ruby/lib/ruby/1.8/webrick/server.rb:89:in start' c:/ruby/lib/ruby/1.8/webrick/server.rb:79:instart’
c:/ruby/lib/ruby/1.8/webrick/server.rb:79:in start' c:/ruby/lib/ruby/gems/1.8/gems/rails-1.0.0/lib/webrick_server.rb:69:indispatch’
c:/ruby/lib/ruby/gems/1.8/gems/rails-1.0.0/lib/commands/servers/webrick.rb:59
c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:18:in
require__' c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:18:inrequire’
c:/ruby/lib/ruby/gems/1.8/gems/activesupport-1.2.5/lib/active_support/dependencies.rb:214:in
require' c:/ruby/lib/ruby/gems/1.8/gems/rails-1.0.0/lib/commands/server.rb:28 c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:18:inrequire__’
c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:18:in
require' c:/ruby/lib/ruby/gems/1.8/gems/activesupport-1.2.5/lib/active_support/dependencies.rb:214:inrequire’
./script/server:3
-e:3:in `load’
-e:3

Request

Parameters: {“search”=>{“minor_build_id”=>"", “major_build_id”=>"",
“system_id”=>“1”, “environment_id”=>""}, “commit”=>“Update Results”}

However I’ve found that if I update the “list” action in the results
controller to this longer and uglier version, it works.

def list
@search = Search.new
if request.post?
@search.major_build_id = params[:search][“major_build_id”].to_i()
@search.minor_build_id = params[:search][“minor_build_id”].to_i()
@search.environment_id = params[:search][“environment_id”].to_i()
@search.system_id = params[:search][“system_id”].to_i()
end
end

This seems a bit long winded and I’m sure there is a simpler and more
elegant way. Is there something I’m missing?

thanks

Iain


#2

Hi –

On Fri, 10 Feb 2006, Iain Rose wrote:

else
@search = Search.new(params[:search])

What you’ve done is equivalent to:

class C
end

c = C.new(“arg”) # wrong # of arguments: 1 for 0

You’d need to write an initialize method – for example

class C
def initialize(*x) # optional argument x
# do whatever here
end
end

Similarly, in your Search class, you would need to define initialize,
probably to handle an optional argument (since it looks like you want
to be able to call it with or without).

 @search.minor_build_id = params[:search]["minor_build_id"].to_i()
 @search.environment_id = params[:search]["environment_id"].to_i()
 @search.system_id = params[:search]["system_id"].to_i()

end
end

This seems a bit long winded and I’m sure there is a simpler and more
elegant way. Is there something I’m missing?

If you do something like this in the Search class:

class Search
attr_accessor :major_build_id, :minor_build_id,
:environment_id, :system_id

 def initialize(*search_hash)
   if search_hash
     search_hash.each do |key,value|
       send("#{key}=", value)  # This calls the appropriate
                               # writer method, matching the key
     end
   end
 end

end

then you could do:

@search = Search.new(params[:search])

and/or

@search = Search.new

in the controller, depending on conditions, etc.

(It seems a bit anomalous to have this Search class among the models,
but that’s another matter :slight_smile:

David


David A. Black (removed_email_address@domain.invalid)
Ruby Power and Light (http://www.rubypowerandlight.com)

“Ruby for Rails” chapters now available
from Manning Early Access Program! http://www.manning.com/books/black


#3

Thanks for the advice.

Can I ask why you don’t need to do this when using models that exist in
the
db. For example, when I use the scaffold generator to create a model
called
Search in a controller called Results, I get this in the controller …

class ResultsController < ApplicationController

def create
@search = Search.new(params[:search])
if @search.save
flash[:notice] = ‘Search was successfully created.’
redirect_to :action => ‘list’
else
render :action => ‘new’
end
end

I’m not intending to use scaffolding throughout my app but it proves it
can
work out of the box (sometimes). The class definition of the Search
model
doesn’t have an initialize method. Does it just inherit something
simliar to
your suggestion from it’s super class?

Also, as this is my first attempt at a Rails app (I’m branching out on
my
own after working through the agile book), can you explain what you mean
by

It seems a bit anomalous to have this Search class among the models

I’d like to start on the right tracks and not get into bad habits.

Thanks again for the advice.

Iain


#4

David is right. The scaffolding code is like that because it expects
Search to be an ActiveRecord subclass. It’s ActiveRecord that
provides the ability to call new with a hash. If you’re not
subclassing ActiveRecord, you need to implement that yourself.

Cheers,

Pete Y.