Editing Multiple Records in Rails

I recently had a requirement to create a single form with data from more than one record. This is a simple request, but I had never done it before in Rails.

After experimenting for a while (and reading quite a few forum posts and StackOverflow answers) I came up with a working solution. Hopefully this will save someone a little time in the future.

First, let’s create a simple Rails app for managing users. Each user will have a first name, last name, and e-mail address. I’m using scaffolding to generate the code.

rails new multi_edit
cd multi_edit
bundle install
rails g scaffold User first_name:string last_name:string email:string
rake db:migrate

Next, add the new routes for editing all users. I tried to stick to the RESTful convention with these. I’m just using the word ‘all’ in place of the :id.

match 'users/all/edit' => 'users#edit_all', :as => :edit_all, :via => :get
match 'users/all' => 'users#update_all', :as => :update_all, :via => :put

Now, let’s add the edit_all method to our UsersController to get started. The only thing it needs to do is get all users.

def edit_all
  @users = User.all
end

Next, we build the form for editing all users.

<%= form_for :user, :url => update_all_path, :html => { :method => :put } do %>
  <table>
    <tr>
      <th>First Name</th>
      <th>Last Name</th>
      <th>E-Mail</th>
    </tr>
    <% @users.each do |user| %>
      <%= fields_for "user[]", user do |user_fields| %>
    <tr>
      <td><%= user_fields.text_field :first_name %></td>
      <td><%= user_fields.text_field :last_name %></td>
      <td><%= user_fields.email_field :email %></td>
    </tr>
      <% end %>
    <% end %>
  </table>

  <div class="actions">
    <%= submit_tag %>
  </div>
<% end %>

The interesting part of this code starts around line 9. As expected, we iterate over the users with @users.each.

The next line tells Rails to name the fields for each user with array notation. For example, user_fields.text_field :first_name will output a text field named user[1][first_name].

The params hash will include a ‘user’ key that contains a hash of information for each user. The key for each of these hashes will be the user id.

Now that we know what the params will look like, it’s pretty straight-forward to write the update_all method.

def update_all
  params['user'].keys.each do |id|
    @user = User.find(id.to_i)
    @user.update_attributes(params['user'][id])
  end
  redirect_to(users_url)
end

We iterate over each key in params['user'], then find and update the user associated with that id. I am leaving error checking as an exercise for the reader…

The complete source code for this simple application is on my GitHub page at https://github.com/anthonylewis/multi_edit

12 thoughts on “Editing Multiple Records in Rails”

  1. Hey, great article. Not sure the version of Rails you’re using when you put this together, but I was running into some issues with your post, and it turned out to be the use of single quotes in the controller.
    params[‘user’].keys.each do |id|

    should actually be

    params[“user”].keys.each do |id|

    Note the use of double quotes rather than single. Other than that it was extremely helpful!

  2. Anthony, thanks for the great post. I have one question (I posted on StackOverflow and referenced your site). I am using Rails 4 and it requires defining permissible fields inside the controller. I am running into an error and was hoping you might be able to help? Thank you!

  3. Hey again, Anthony. I think I found a solution for Rails 4 strong parameters. I wanted to share just in case your other readers may want to know, too. I modified the code to fit your model above.


    def update_all
    params['user'].keys.each do |id|
    @user = User.find(id.to_i)
    @user.update_attributes(user_params(id))
    end
    redirect_to(users_url)
    end

    This should be added to the bottom of the controller the update_all action is in:


    def user_params(id)
    params.require(:user).fetch(id).permit( :first_name, :last_name, :email )
    end

  4. Magnificent, thanks so much Anthony. Really helped a newbie out. I’m learning to love Rails but things like params are still bending my mind a little. Thanks due also to Bob Walden & Roy McKenzie for sharing their tips too – very generous of them and I believe Roy’s tip is required to make this work with Rails 4.

  5. This was brilliant thanks!

    The only problem I encountered is that I’m using “friendly-idized” resources, which means my ids are actually slugs. It caused trouble with Rails 4 strong parameters, but I fixed it by defining a new “params” method using the slugs:
    @model.update_attributes(
    params.require(
    :model
    )[key]
    .permit(

    )

    Not too DRY but alright!

    Thanks a lot,
    Cheers

  6. This article was of great inspiration for me,
    especially this line:
    fields_for "user[]", user do |user_fields|

Comments are closed.