0

I've got a links array that I'm saving to a database. The problem is that the records aren't saved in the order of the array ie links[1] is saved before links[2] and so on...

This is a example from the view file:

<p>
  <label for="links_9_label">Label</label>
  <input id="links_9_name" name="links[9][name]" size="30" type="text" />
  <input id="links_9_url" name="links[9][url]" size="30" type="text" />
</p>

And this is my controller:

def create
    @links = params[:links].values.collect { |link| @user.links.new(link) }

    respond_to do |format|
         if @links.all?(&:valid?)
         @links.each(&:save!)

        flash[:notice] = 'Links were successfully created.'
        format.html { redirect_to(links_url) }
      else
        format.html { render :action => "new" }
      end
    end
  end

Thanks in advance!

Alfred

2
  • why do you need to save them in order? i'm just curious :] Commented Mar 11, 2010 at 17:52
  • Before I get proper sorting functionality in place I just want to save them in the order they were filled in for simplicitys sake. Commented Mar 11, 2010 at 18:48

2 Answers 2

1

The reason your links aren't being stored in order is that you're not presenting them to the db in order.

-- The param object is not an array, even though, to an extent it might look like one. Rather, they are a hash where the keys are integers. You can tell this is true because you need to use

params[:links].values.collect

if it was an array, you'd use

params[:links].collect

Any time you use .values method, the key order is indeterminate.

Solution

I agree with @p.g that you should be very careful about using db id's as an order. Eg suppose you want to change the order later? I often have 'list_order' as a field in my models.

To reorder the params, and save in order of the key, try the following:

links_param = params[:links]
ordered_keys = links_param.keys.sort
@links = ordered_keys.collect {|key| @user.links.new(links_param[key])}

Added: also note that the keys might well come in as strings, not integers. So if you have more than 10 of them, might be an idea to sort them as integers:

ordered_keys = links_param.keys.sort{|a,b| a.to_i <=> b.to_i}

Added in response to comment about saving the "display_order" --

First, add new field to model, :display_order. Be sure to add an index on the field since you'll be sorting on it.

Then, in your controller, you need to expose the key to the model. Eg something like this:

 links_param = params[:links]
 links_params.keys.each{|key|links_params[key][:display_order] = key.to_i}

Now when you build your user.link object, the display_order param will be set too.

Sign up to request clarification or add additional context in comments.

2 Comments

Don't get that code to work, still a strange order... ...how can I fetch the number from links[] and put in a seperate column?
Got more than 10 and with that code snippet it worked flawlessly! Thanks a lot!
0

Alter your schema so it has a display_order column or something similar, and have this pushed through as a hidden input on the front end.

Relying on the id column for ordering is discouraged, as it is essentially an arbitrary value created by the DB, which happens to follow a logical sequence most of the time. Having a separate column for the order won't break DRYness because it is (technically) for a different purpose.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.