Simon Bingham
Simon Bingham

Reputation: 1310

Rails 4 executing two queries without overwriting same records

I'm learning Rails 4 by creating a simple content management system. My page structure uses the Nested Set Model and I'm trying to create a controller action so pages can be moved up and down in the page structure (i.e. left and right in the hierarchy). Here's my controller action:

# GET /admin/pages/move
def move
  if params[:direction] == 'up'
    ActiveRecord::Base.transaction do
      @page = Page.find(params[:id])
      @previous_sibling = @page.get_previous_sibling
      @difference = @page.left_value - @previous_sibling.left_value
      Page
        .where('left_value >= :left_value AND right_value <= :right_value', {:left_value => @previous_sibling.left_value, :right_value => @previous_sibling.right_value})
        .update_all('left_value = left_value + #{@difference}, right_value = right_value + #{@difference}')
      Page
        .where('left_value >= :left_value AND right_value <= :right_value', {:left_value => @page.left_value, :right_value => @page.right_value})
        .update_all('left_value = left_value - #{@difference}, right_value = right_value - #{@difference}')
    end
    flash[:success] = 'The page has been moved up.'
  elsif params[:direction] == 'down'
    # TODO: add code to move page down
    flash[:success] = 'The page was moved down.'
  end
  redirect_to admin_pages_path
end

The problem I'm having is the second query updates the records that have already been updated in the first query. Is there a way of effectively running both queries at once instead of one at a time so the records updated in the first query are not updated again in the second query?

Upvotes: 0

Views: 44

Answers (1)

SHS
SHS

Reputation: 7744

Since you are updating differently in both update_all methods, you will have to run two different queries. Either that or involve some complicated SQL code.

As for not updating the same records twice, you could check which IDs you're updating in the first go and exclude them in the second query. Here's an example (with bad variable names):

pages1 = Page.where(conditions1)
pages1_ids = pages1.pluck(:id)
pages1.update_all(update_conditions1)

pages2 = Page.where("id NOT IN (?)", pages1_ids).where(conditions2)
pages2.update_all(update_conditions2)

Upvotes: 1

Related Questions