Design

Sunday, October 5, 2014

Sorting Backbone subviews in Rails

I recently completed my solo project at App Academy, which can be seen here on Heroku. My polling application has two different index views. One index view is if the current user has not answered the poll, sorted with the most recent at the top. The other index is for the polls they have answered, sorted by their most recently answered polls on top. Each index is a Backbone composite view, consisting of subviews. Every line on the table of polls is a subview, so sorting them turned out to be different than what I first tried. I also had infinite scroll, which probably should have given me a clue on the correct way to solve the problem.

The first place I looked was the Backbone documentation. 
If you define a comparator, it will be used to maintain the collection in sorted order. This means that as models are added, they are inserted at the correct index in collection.models
That seemed to be what I wanted, so I defined a comparator. I wanted the most recent at the top, which could have been done with created_at, but more simply could be done by descending id. Comparator does accept a function with a negative value. Unfortunately, I could not get the order to change in my view. The collection was sorted correctly in my browser console, but my JSON API was not in the correct order. So then I realized my API controller was to blame.
def index
    @polls = Poll.all
 end
The most basic index following RESTful conventions youve probably seen in every Rails tutorial. There is a lot me we could do with this however. Mine ended up as:
def index 
    if params[:answered] == "false" 
        @polls = Poll.where.not(id: current_user.answered_polls).order(id: :desc) 
    else 
        @polls = current_user.answered_polls.order("responses.id DESC") 
    end

    @polls = @polls.includes(:responses).page(params[:page]) 
    @page_number = params[:page] 
    @total_pages = @polls.total_pages 
    render :index 
end
Those last three instance variables were for pagination. I explicitly rendered index here for consistency. All my other actions were rendering JSON, butindex is rendering JSON that I customized in Jbuilder. What is cool here is how both indexes used the association answered_polls differently. In the first view, the id in the resulting table is the poll.id, which would be in the same order that a poll was created in the database. The second example was ordering when the user responded to the poll. I only wanted to see the polls they had answered, but I wanted the id of the responses, not the poll. I could not access responses.id as a symbol, the way I did in the first example. ActiveRecord is pretty good at it's job, but sometimes you have to give it some SQL in quotes. In order to figure out the filtering and ordering of these two index views, I had to think about how I'd do it in pure SQL. Lucky for me, I love SQL and this solved my sorting problems.

No comments:

Post a Comment