views:

38

answers:

1

I'm having an issue writing a controller action that takes Post ids passed as a parameter and sorts them into a specific order before publishing them.

The Posts have a position attribute (I'm using acts_as_list for sorting), and are either published or unpublished (searchable with the named_scopes Post.published and Post.unpublished, accordingly).

Essentially, there is a JavaScript interface that allows users to drag unpublished posts into a queue, and publish them by passing the ids as a post_ids parameter to a controller method that looks like this:

def publish
  Post.update_all(['published=?', true], :id => params[:post_ids])
  redirect_to admin_path
end

Publishing the posts like this works fine. What I need to do next is to sort the Posts by their position in a specific order, and this is where I'm having problems.

Let's say a user drags post 5, then post 3, then post 7 into the queue and clicks "Publish."

What I want to do is then organize all Posts to have 5, 3, 7 at the first positions in order, and then the rest of the Post objects in the order they were already in, so sorting by Post.position would be [5, 3, 7, ...the rest of the posts in order here...]

Then if the user were to drag two new posts into the queue and click "Publish" (this time let's say posts 2 and 4), the posts should be in the order [2, 4, 5, 3, 7, ...the rest of the posts in order here...]

Then for a final example, let's say the user moves posts 10, 1, and 12 onto the queue and publishes, the order should be [10, 1, 12, 2, 4, 5, 3, 7, ...the rest of the posts in order here...] etc...

I'd show the code I've been working on, but I'm not sure it'd be helpful since I haven't gotten it to sort correctly. But essentially I imagine this is an issue of taking two arrays, the first being all Posts and the second being the Posts to publish, and putting each item in the Posts to publish array at the beginning of the all Posts array, and then publishing. I just can't seem to get it to work. Any help here would be greatly appreciated, and I thank you in advance for your time!

Edit In case it helps, here's the code I've written so far. In testing, it seems that this method sorts the posts from the queue correctly the first time, but any subsequent posts that are published don't move to the front of the published Posts list.

def publish
  if params[:to_publish].present?
    # :to_publish are the posts dragged into the queue in order.
    # Here I'm cleaning up the Javascript input and then iterating 
    # through them to update their sort order.
    params[:to_publish].to_s.split(",").uniq!.each_with_index do |id, index|
      Post.update_all(['position=?', index + 1], ['id=?', id])
    end
  end
  # :post_ids are the posts to be published, order is irrelevant.
  # For client-side reasons they're passed as a separate parameter.
  Post.update_all(['published=?', true], :id => params[:post_ids])
  redirect_to admin_path
end
A: 

params[:to_publish].to_s.split(",").uniq!

Here, why do you do unique check? Is it a defensive measure?

Also note that uniq! returns nil if no duplicates are found, which causes your code to throw nil reference error if the array has no duplicates.

If you have a rescue block in your code that swallows this nil reference error, you are in trouble!

Vijay Dev
Yes, thanks. That hacky split and uniq! line is just a quick workaround fix due to some sloppy JavaScript currently existing on the client-side. When I clean the JavaScript code up, I shouldn't need to call uniq!, but it's just a lower priority for me right now. Thanks again for this tip though.
Bryan Woods