hqt
hqt

Reputation: 30284

Rails : sort for the specific column

I'm designing a table on view. For instance, they have two columns are ID and name. When a user clicks to the ID column, I want the data will be sorted by ID. Similarly, if a user clicks name column, the data will be sorted by name.

My question is :

Is there any way to put this into the model (database model), hence, when user click one column, its status will be saved and the database will look at this to return record according to this status.

if not, how I put this code in view.

Please help me.

Thanks :)

Upvotes: 1

Views: 5254

Answers (1)

Sully
Sully

Reputation: 14943

Look at this railscasts #228 http://railscasts.com/episodes/228-sortable-table-columns

def sortable(column, title = nil)
  title ||= column.titleize
  css_class = column == sort_column ? "current #{sort_direction}" : nil
  direction = column == sort_column && sort_direction == "asc" ? "desc" : "asc"
  link_to title, {:sort => column, :direction => direction}, {:class => css_class}
end

When you have functional sort columns, you then will need to save it to the db

A basic table with: user_id, page_name (or table_name), sort_column, sort_direction

Then when the user loads a page you would check against the saved settings and load them if they exist, if they don't you can load a default.

This is the idea, I do not have time to write the code for it, but it should be fairly straight forward.

Update:

Since I had to do this at work, I will post my code.

The railscast above implements the following three functions, which allow for sorting on a column.

application_controller.rb/or specific_controller.rb

def sort_column
  Product.column_names.include?(params[:sort]) ? params[:sort] : "name"
end

def sort_direction
  %w[asc desc].include?(params[:direction]) ? params[:direction] : "asc"
end

And the controller that uses it

def index
  @products = Product.order(sort_column + " " + sort_direction)
end

Now, in order to remember what the user selected for the sort and to use that instead of always loading the default sortable column we need to create a table for the user_preferences

create a migration for the preference table like

create_table :user_preferences do |t|
  t.string :action
  t.string :preference

  t.references :user
end
add_index :user_preferences, :user_id

When we search now (path -> 'specific_controller#index?direction=asc&sort=name') we need to save/update the user's preference

def index
  preference = UserPreference.find_by_user_id_and_action(User.current_user.id, params[:action])
  #Save/update preference based on column sort
  if params[:sort]
    unless preference.nil?
      preference.update_attribute(:preference, "#{params[:sort]},#{params[:direction]}")
    else
      preference = UserPreference.new(:user => User.current_user, :preference => "#{params[:sort]},#{params[:direction]}", :action => params[:action])
    end
  end
  populate_table_based_on_preference(preference)
end

def populate_table_based_on_preference(preference)
  unless preference.nil?
    @products = Product.order(preference.preference.split(',')[0]+ " " + preference.preference.split(',')[1])
  else
    @products = Product.order(sort_column + " " + sort_direction)
  end
end

Then we need to update our methods (sort_column/direction -> What column are we sorting/ Which direction? )

def sort_column
  #What are we sorting on?
  preference = UserPreference.find_by_user_id_and_action(User.current_user.id, params[:action])
  unless preference.nil?
    preference.preference.split(',')[0]
  else
    Product.column_names.include?(params[:sort]) ? params[:sort] : "name" 
  end
end

def sort_direction
  preference = UserPreference.find_by_user_id_and_action(User.current_user.id, params[:action])
  #what is the search direction
  unless preference.nil?
    preference.preference.split(',')[1]
  else
    %w[asc desc].include?(params[:direction]) ? params[:direction] : "asc" 
  end
end

Upvotes: 3

Related Questions