开发者

'Unknown key(s)' ArgumentError

I'm working on a moderating feature for my application, which is based on a basic scaffold structure. What I need, is to edit several records with the boolean parameter publised on false. In moderate.html I'm getting the list of all unpublished entries with the ability to change their parameters which, what and published. The error appears, when I'm trying to save the changes through the complete action.

ArgumentError in NamesController#complete

Unknown key(s): 7, 1, 4

The "7, 1, 4" are id of my unpublished records.

Here are the parts of my code:

#names_controller.rb

    def moderate
     @names = Name.find(:all, params[:name_ids], :conditions => {:published => false})
      respond_to do |format|
        format.html { render :action => "moderate" }
开发者_如何学C         format.xml 
       end
     end

def complete
     @names = Name.find(params[:name_ids])
     @names.each do |name|
       name.update_attributes!(params[:name].reject { |k,v| v.blank? })
     end
     flash[:notice] = "Updated records!"
     redirect_to names_path
   end


#moderate.html.erb
<% form_tag complete_names_path do %>  
  <% @names.each do |name| %>
    <fieldset>
    <% fields_for "name_ids[#{name.id}]", name do |name_fields| %>
    <%= name_fields.text_field :which %>
    <%= name_fields.text_field :what %>
    <%= name_fields.check_box :published %> 
    <% end %>
    </fieldset>   
  <% end %>  
<%= submit_tag "Ok" %>
<% end %>/


#routes.rb
ActionController::Routing::Routes.draw do |map| 
  map.connect 'moderate', :controller => 'names', :action => 'moderate'
  map.resources :names, :collection => { :complete => :put}
  map.root :names
  map.connect ':controller/:action/:id'
  map.connect ':controller/:action/:id.:format'

I understand, that there's something wrong with the name_ids, but don'nt understand, what should I do. Thank you in advance.

ruby 1.8.7 (2009-06-12 patchlevel 174)

[universal-darwin10.0] Rails 2.3.5

Rails log for moderate and complete actions:

Processing NamesController#moderate (for 127.0.0.1 at 2010-10-16 21:36:42) [GET] [4;35;1mName Load (0.6ms)[0m [0mSELECT * FROM "names" WHERE ("names"."published" = 'f') [0m Rendering template within layouts/names Rendering names/moderate Completed in 12ms (View: 7, DB: 1) | 200 OK [http://localhost/moderate]

Processing NamesController#complete (for 127.0.0.1 at 2010-10-16 21:36:49) [POST] Parameters: {"commit"=>"Ok", "authenticity_token"=>"CtmsjIavksOMSIArrdovkkzuZzHVjkenFFMO5bHIvgg=", "name_ids"=>{"7"=>{"published"=>"0", "what"=>"Партия", "which"=>"Крутая"}, "1"=>{"published"=>"1", "what"=>"Россия", "which"=>"Единая"}, "4"=>{"published"=>"0", "what"=>"Организация", "which"=>"Молдавская"}}}

[4;36;1mName Load (0.4ms)[0m

[0;1mSELECT * FROM "names" WHERE ("names"."id" IN (7,1,4)) [0m

NoMethodError (You have a nil object when you didn't expect it! You might have expected an instance of Array. The error occurred while evaluating nil.reject):

app/controllers/names_controller.rb:47:in complete'

app/controllers/names_controller.rb:46:in each'

app/controllers/names_controller.rb:46:in `complete'

Rendered rescues/_trace (110.3ms) Rendered rescues/_request_and_response (0.5ms) Rendering rescues/layout (internal_server_error)


Likely you need to get just the keys from the name_ids hash. Try:

@names = Name.find(params[:name_ids].keys)

A separate problem is your reference to params[:name], which is nil. Did you mean (EDIT: use to_s to match the params key, lol):

@names.each do |name|
  name.update_attributes!(params[:name_ids][name.id.to_s].reject { |k,v| v.blank? })
end

EDIT (brief-ish explanation):

What was happening was that you had a nested hash in the params, params[:name_ids]. It looked like:

"name_ids"=>{"7"=>{"published"=>"0", "what"=>"Партия", "which"=>"Крутая"}, "1"=>{"published"=>"1", "what"=>"Россия", "which"=>"Единая"}, "4"=>{"published"=>"0", "what"=>"Организация", "which"=>"Молдавская"}}

An ActiveRecord 'find' method can take an array of ids, but not a hash of values. What you were originally submitting to 'find' in this line:

@names = Name.find(params[:name_ids])

...was the value for params[:name_ids]:

{"7"=>{"published"=>"0", "what"=>"Партия", "which"=>"Крутая"}, "1"=>{"published"=>"1", 
"what"=>"Россия", "which"=>"Единая"}, "4"=>{"published"=>"0", "what"=>"Организация", 
"which"=>"Молдавская"}

When what you wanted was:

@names = Name.find(['7','1','4'])

which is what calling params[:name_ids].keys gives you.

The second problem was this line:

name.update_attributes!(params[:name].reject { |k,v| v.blank? })

There was no value ':name' in params, so calling 'reject' on it cause the 'no method' error -- there is no 'reject' method on the nil object. What you wanted was to update the attributes for the 'name' that corresponded to the particular name in the loop. This meant you wanted to get the values out of params[:name_ids][:id] where :id was the id of 'name'.

It all goes back to the way fields_for created the params to begin with. This line:

<% fields_for "name_ids[#{name.id}]", name do |name_fields| %>

meant that params would contain a hash called 'name_ids', with keys corresponding to name.id, that themselves would contain hashes of attributes that ActiveRecord could use in the update_attributes method.

There's a good bit of the famous Rails magic to keep track of in there -- does that help?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜