I have a 'Sort By' dropdown on an events page where users can view a number of events and I'd like to allow users to Sort the events by Name (Alphebetical), Date (Created_At), and perhaps (Number of people attending hi/low).
How can I achieve this? I'm guessing with a default scope: order, Event.where(:name, ASC) for example but i'm not sure as I've never done this before.. Also how would I display/use the scope in the dropdown?
I recommed you the very-usefull gem has_scope:
https://github.com/plataformatec/has_scope
What you could do with it:
class Event < ActiveRecord::Base
scope ordered, lambda do |attribute, order|
return where("FALSE") unless self.attribute_names.include?(attribute.to_s)
order(attribute.to_sym, order.to_sym
end
class EventsController < ApplicationController
has_scope :ordered do |controller, scope, value|
scope.ordered(value, :desc)
end
# view
options = [['Name', 'name'], ['Date', 'date']]
select_tag("ordered", options_for_select(options, selected: params[:ordered]), onchange: "window.location.href = window.location.origin + window.location.pathname + '?ordered=' + $(this).val();"
I did not test the view, you might have to change the code a little bit. The javascript redirect does not support extra GET params!
Have a look at the RailsCasts
http://railscasts.com/episodes/240-search-sort-paginate-with-ajax
This also includes pagination and simple searches. However, you can take from it the part that you're looking for.
For active record you just need to append .order(symbol) to your active record query.
for alphabetic you could do.
Object.where(ARRGUMENT).order(:name)
or for all
Object.order(:name)
You don't need to use a scope for this it is over kill for something this simple.
If you want to create an interactive table then you might want to consider a Javascript solution. This is the one that has worked the best for me.
https://datatables.net/
I have used and currently use this gem with great success.
https://github.com/rweng/jquery-datatables-rails
Related
I have a model called Page. The users are able to specify attributes whenever they create a Page. Ideally, they will choose from a list of attributes and assign them to the Page.
My first though was to create as many columns as attributes the user is able to select, and basically marking them as true/false if it has been selected.
However, I have a feeling that I might be missing a better approach. I have also used at HSTORE, but at the end of the day, I would also need to do something like:
attributes: { 'attribute1' => 'true', 'attribute2' => 'false' } and I am not sure if that is appropriate.
I will use those attributes in order to select pages, so I should be able to say something like:
Page.where(attribute1 is true).where(attribute2 is false).where(...)
How should I store those attributes in my Page model?
The acts_as_taggable_on gem might be of help to you.
You would declare your model as taggable on your attributes as follows:
class Page < ActiveRecord::Base
acts_as_ordered_taggable_on :attributes
end
And your example query would be something like this:
Page.tagged_with(["attribute1"]).tagged_with(["attribute2"], :exclude => true)
The Gem is very well documented here.
Let's say I have a table posts, and another table reviews that has a post_id and a rating (integer).
How can I add a filter to app/admin/post.rb which returns posts with a certain total score? (e.g. SUM(reviews.rating) GROUP BY (posts.id)). I want the filter to show up on the right side of the index, along with the other filters, and ideally to function as a range input.
To be clear, when I say "filter", I mean the ActiveAdmin filter method which adds filters to the right sidebar on the index page.
I created a scope in Post which returns posts with scores, but I haven't been able to find a way to use that in an ActiveAdmin filter.
Note: I rewrote my example because my original one didn't capture the complexity of the question.
It's common to override scoped_collection to join associated records to increase performance:
ActiveAdmin.register Post do
controller do
def scoped_collection
super.includes :author, :publisher
end
end
end
Since the entire collection now has author and publisher included, you can have a scope that queries those:
scope :random_house do |scope|
scope.where publishers: {name: 'Random House'}
end
I haven't come up with a proper solution to this question, but I have found a workaround.
I can change the scoped_collection based on a query param, and simply pass the param in when I want to use it. For example, if I have a scope with_rating(x), which returns posts with a score of at least x, I can write:
controller do
def scoped_collection
if params[:with_rating]
super.with_rating(params[:with_rating])
else
super
end
end
end
Then I can go to /admin/posts?with_rating=100 and get back posts with a rating of at least 100.
Thanks to #seanlinsley for making me aware of the scoped_collection method that I used in this solution.
Use counter cache column to store the comments count
http://railscasts.com/episodes/23-counter-cache-column
Then the column will get updated each time a comment is created to that post.This would also help in increasing the performance of search.
I'm fairly new to both Ruby and Rails, picking up a side-project and working out best-practices. I'm wondering what the recommended approach to this problem might be.
I have an array of widgets with associated grades given by users. When displaying the list of widgets in the view I want to present the grade given, if any, by the logged in user.
What I've got working looks like this, but feels dirty. In my controller I grab some widgets and associated grades (all grades used elsewhere), and from that data I generate a myGrades hash:
#widgets = Widget.include(:grades).limit(20)
#myGrades = Hash[#widgets.collect{ |w| [w.id,w.grades.select{ |g| g.user_id==site_user.id}].delete_if{|k,v|v.nil?}]
In my haml view, when presenting the widgets, I have something like this:
-if #myGrades.has_key?(widget.id)
.mygrade #myGrades[widget.id].value
But, I feel I would be better off with methods like "have I graded this?" and "give me MY grade for this" on my graded widget, without the myGrades middle-man.
Eventually, though, lots of different objects will be graded, so how should I best implement these methods in Rails so they can be applied to any graded models?
You can do the following:
#my_grades = Widget.include(:grades).where(grades: {user_id: site_id}).limit(20)
As #sameera207 pointed out, you should move this complex query in your model: create a scope.
class Widget < ActiveRecord::Base
scope :for_user, lambda do |user, limit = 20|
includes(:grades).where(grades: {user_id: user.try(:id) || user}).limit(limit)
end
And use it like this:
Widget.for_user(user_id)
# works also with a user object:
Widget.for_user(user)
# or if you want a custom limit:
Widget.for_user(user_id, 50)
I'm trying to override the default ordering of the belongs_to drop-downs for the new/edit forms. I'd like to order the belongs_to relationships to name instead of the default id desc.
Based on the wiki (https://github.com/sferik/rails_admin/wiki/Associations-scoping) I have this:
field :theme do
associated_collection_cache_all false
associated_collection_scope do
Proc.new { |scope|
scope = scope.reorder("themes.name ASC")
}
end
end
end
The reorder seems to be ignored while where statements are picked up.
Are you sure the column you're trying to sort by is 'names' and not 'name'?
A good way to debug this would be to open a rails console and see if your reorder actually works this way.
Theme.all.reorder("themes.names ASC")
I'm guessing that probably won't work as expected and you need to tweak the reorder.
If you want to see the SQL it's creating, you can do this.
Theme.all.reorder("themes.names ASC").to_sql
That might give you more information about whats going wrong.
I have a model with some scopes defined on it:
class Alarm < ActiveRecord::Base
scope :open_alarms, where("state != ?", AlarmStates::STATELIST[-1])
scope :new_alarms, where('state is null')
scope :site_alarms, lambda{ |site| where(:mac_address => site.mac_address)}
#etc
end
These scopes are all Relation objects, so I should be able to chain them in a with_scope call. But I can't get it all to work. I have been trying something along the lines of
Alarm.with_scope(:find => Alarm.open_alarms){all}
which, AFAIK, should apply the Relation Alarm .open_alarms onto the find, and then effectively find all alarms matching the open_alarms scope. But I get an 'unidentifed variable or method "all" for Main:Object' error when I try this. I have tried a whole series of variants, but nothing seems to get there.
Where I am trying to get to is being able to chain a series of scopes, then apply pagination so I can output pages of alarms.
Any help would be very much appreciated.
Thanks,
Steve
#alarms = Alarm.open_alarms.page(params[:page])
#alarms = Alarm.open_alarms.site_alarms("http://sample.me").page(params[:page])
(Using gem will_paginate or kaminari).
You seem to be using pre 3.2 code to do your query.