Kyle
Kyle

Reputation: 1173

Create multiple objects simultaneously using for loop in controller

I have a Word model with one column: word. I have a form that creates an @word object when submitted.

words/_form.html.erb

<%= form_for(@word, :remote => (params[:action] == 'new' ? true : false)) do |f| %>
  <fieldset>
    <div class="field">
      <%= f.text_field :word, :required => true %>
    </div>
  </fieldset>

  <div class="actions">
    <%= f.submit :disable_with => 'Submitting...' %>
  </div>
<% end %>

words/create.js.erb

$('#words').prepend( '<%= escape_javascript(render @word) %>' );
$('#new-word-form-container').find('input:not(:submit),select,textarea').val('');

I'd like to shorthand the creation of multiple words simontaniously on one form submission (i.e. instead of having to resubmit to create each individual word).

I have a method in my Word model that splits the string into an array of words (separated by a comma or space).

class Word < ActiveRecord::Base

attr_accessible :word

  # Split Words method splits words seperated by a comma or space
  def self.split_words(word)
    # Determine if multiple words
    if word.match(/[\s,]+/)
      word = word.split(/[\s,]+/)    # Split and return array of words
    else 
      word = word.split              # String => array 
    end 
  end

end

I'm trying to use a for loop within my create action to step through each array element, and create an @word object for the element.

class WordsController < ApplicationController
respond_to :js, :json, :html

def create
  split = Word.split_words(params[:word])

  split.each do |w|
    @word = Word.create(params[:w])
    respond_with(@word)
  end
end

I'm currently getting a HashWithIndifferentAccess error, as listed below.

Started POST "/words" for 127.0.0.1 at 2014-06-10 13:09:26 -0400
    Processing by WordsController#create as JS
      Parameters: {"utf8"=>"✓", "authenticity_token"=>"0hOmyrQfFWHRkBt8hYs7zKuHjCwYhYdv444Zl+GWzEA=", "word"=>{"word"=>"stack, overflow"}, "commit"=>"Create Word"}
    Completed 500 Internal Server Error in 0ms

    NoMethodError (undefined method `match' for {"word"=>"stack, overflow"}:ActiveSupport::HashWithIndifferentAccess):
      app/models/word.rb:9:in `split_words'
      app/controllers/words_controller.rb:36:in `create'

Any help is greatly appreciated.

Upvotes: 1

Views: 1440

Answers (2)

mrageh
mrageh

Reputation: 138

In your create action in the words controller, you fetch the words from the params which gives you back a parameter object. The parameter object is a hash like object that inherits from ActiveSupport::HashWithIndifferentAccess. Then you try and call the match method on your parameter object and it does not know how to respond to it, so you get a NoMethodError.

Checkout http://api.rubyonrails.org/classes/ActionController/Parameters.html

The first thing you need to do is pass params[:word][:word] instead of params[:word], this should give you back a string object and this method should now work.

It also looks like you might run into another problem in the each loop in create as params[:w] might return nil. You should instead just pass in w because that will be each word in the array you are iterating over and if am not mistaken you want to create a word object for each word.

def create
 split = Word.split_words(params[:word][:word])

 @words = split.map do |w|
   Word.create(word: w)
 end

 respond_with(@words)
end

Upvotes: 2

phoet
phoet

Reputation: 18845

class WordsController < ApplicationController

  respond_to :js, :json, :html

  def create
    @words = params[:word].split.map { |word| Word.create(word) }
    respond_with(@words)
  end
end

Upvotes: 0

Related Questions