I'm defining #courses variable in my Course#index method in several ways:
def index
#courses = Course.order("title")
# #courses = Course.all
# #courses = Course.paginate(page: params[:page] )
# #courses = Course.order("subject_id").order("student_level_id")
end
I have a partial view to display the set: _course.html.slim:
li
=> link_to(course.title.capitalize, course)
The problem is, while displaying the Courses set, the order doesn't change regardless which way I define my #courses. Although in rails console there is a difference in order.
UPDATE
This is a courses/index.html.slim, it is a basic example from Hartl's tutorial.
ul.users
= render #courses
By the way, in another place (on homepage /static_pages/home.html.slim), this same code snippet results in other ordering.
So, I am wondering, maybe it is some kind of caching problem....
What might be the problem? Thank you in advance!
I found out what I was doing wrong.
There were two separate #courses instances defined, each in two different controllers, so because of this I got discrepancies in answers, because only one instance was ordered.
To stay DRY, I moved ordering from a controllers
#courses = Course.order("subject_id").order("student_level_id")
to Course model:
default_scope order: "courses.subject_id, courses.student_level_id"
and changed all definitions in my controllers to a simple Course.all.
Also, I believe I found answer to this question of mine: https://stackoverflow.com/questions/20583858/default-scope-ordering-based-on-associated-models-attributes
Thank you very much for help!
Related
We build a video-section for our users. The user can filter the videos by rating/views/date.
Also the user can decide to hide already seen videos. This is where i struggle a little bit.
right now i have a solution, which is working, but doesnt seem to perform great.
if #filter == "newest"
if #unseen
ids = Videothek::Video.where(videothek_category_id: categories).pluck(:id)
views = Videothek::Video::View.where(user_id: current_user.id).pluck(:video_id)
unseen = ids - views #ids der ungesehenen videos
#videos = Videothek::Video.where(id: unseen).order("created_at DESC")
else
#videos = Videothek::Video.where(videothek_category_id: categories).order("created_at DESC")
end
end
i thought it must be possible to do with a scope, like Videothek::Video.unseen(current_user).order(.....)
A Video has_many Views, but i struggle to get the join running, as i just want the videos, that DONT have an association with an videothek_video_view, where user_id = 1 (or current_user.id).
can somebody help me out?
btw: we are on RoR3
You may use where.not(video_id: [ids]) to make database filter videos user already seen. This method is added since rails 4.
https://robots.thoughtbot.com/activerecords-wherenot
instead of pluck(:id) you may use .ids. I would also move the code somewhere out of controller.
Probably you question would fit better to https://codereview.stackexchange.com/ since you already have working version.
I have a table KmRelationship which associates Keywords and Movies
In keyword index I would like to list all keywords that appear most frequently in the KmRelationships table and only take(20)
.order doesn't seem to work no matter how I use it and where I put it and same for sort_by
It sounds relatively straight forward but i just can't seem to get it to work
Any ideas?
Assuming your KmRelationship table has keyword_id:
top_keywords = KmRelationship.select('keyword_id, count(keyword_id) as frequency').
order('frequency desc').
group('keyword_id').
take(20)
This may not look right in your console output, but that's because rails doesn't build out an object attribute for the calculated frequency column.
You can see the results like this:
top_keywords.each {|k| puts "#{k.keyword_id} : #{k.freqency}" }
To put this to good use, you can then map out your actual Keyword objects:
class Keyword < ActiveRecord::Base
# other stuff
def self.most_popular
KmRelationship.
select('keyword_id, count(keyword_id) as frequency').
order('frequency desc').
group('keyword_id').
take(20).
map(&:keyword)
end
end
And call with:
Keyword.most_popular
#posts = Post.select([:id, :title]).order("created_at desc").limit(6)
I have this listed in my controller index method which allows the the order to show the last post with a limit of 6. It might be something similar to what you are trying to do. This code actually reflects a most recent post on my home page.
I have an index view of a model which I would like to filter by some combination of the model's attributes.
For example, I have a Bill model (not the kind on ducks, the kind you have to pay) that I might filter on payee and/or status.
The model has a scope for each individual attribute, e.g.
scope :bill_status, lambda {|status| where("status = ?", status}
scope :bill_payee, lambda {|payee| where("payee_id = ?", payee.id}
The view allows the user to select zero or more options -- if an option is not selected, it means "don't filter by this".
In the controller, I can do something yucky like this:
def index
status = params[:bill][:status]
payee = params[:bill][:payee]
if status.present? and payee.present?
# chain scopes
#bills = Bill.bill_status(status).bill_payee(payee)
elsif status.present?
#bills = Bill.bill_status(status)
elsif payee.present?
#bills = Bill.bill_payee(payee)
else
#bills = Bill.all
end
# rest of controller action
end
But while this works, it's neither pretty nor easily extensible -- adding a third filter means I now have many more possibilities. I seek beauty and purity.
On the assumption that my scopes are all chainable, it seems like I should be able to do something like
def index
#bills = Bill.all
#bills = #bills.bill_status(params[:bill][:status]) if params[:bill][:status].present?
#bills = #bills.bill_payee(params[:bill][:payee]) if params[:bill][:payee].present?
# rest of controller code
end
'cept it doesn't work because Bill.all is an array. Plus, that's no fun because Bill.all executes the query, which I only want to run once thanks to AREL magic. Should I just define a scope like all_bills (with no conditions?) -- that would be an ActiveRecord::Relation I guess...
Is there a pattern that solves this problem more elegantly? Whenever I have code to do one thing that relies on Model, View and Controller I feel as though I might be doing something wrong. Or as though someone smarter and harder working than I has already solved it :-)
Bonus question: I want this all to work with my paginator of choice, the most excellent Kaminari gem.
All thoughts and ideas welcomed.
I'd do something like this:
proxy = Bill.scoped
if status.present?
proxy = proxy.bill_status(status)
end
if payee.present?
proxy = proxy.bill_payee(payee)
end
#bills = proxy
You can even do then some meta-programming:
#bills = [:status, :payee, ...].inject(Bill.scoped) do |proxy, param|
val = params[:bill][param]
val.present ? proxy.send("bill_#{param}", val) : proxy
end
As I searched for solutions to what seemed like a common problem, I checked out Ryan Bates' RailsCast and found an episode from 3 days ago on Ransack. Ransack is a pretty seriously cool gem for form searching and column sorting, and I think that's the way I am going.
Thanks for the answers here -- I am glad to have learned a couple of great techniques from those who took the time and effort the answer.
This is just a quick question on performance in an sql query using ruby and rails.
Basically I have a parent model and a bunch of children which have the variable of parent_ID.
I first gather all the parents with a specific condition and then I cycle through each parent finding any children that match.
Unfortunately this is incredibly slow and I was wondering if theres any help going in optimizing it.
#parents = Parent.where(:parent_id => 3) #This is passed in from params
#childrenArray =[]
#parents.each_with_index do |parent, index|
#TOOSLOW
#childrenArray[index] = Child.find(:all,:order=>"id",:conditions =>{:parent_ID=> parent.id})
end
One thing I thought is perhaps I should make an array of all the parent Ids to be searched and then do something like
child.find_by_parent_ID(myarrayofnumbershere)
However I don't know if this would be any better.
Any help or advice appreciated.
I'm very new to SQL and ruby. I'm aware a table joins would have been ideal here but I think I'm a bit late in my development to try it now. Also I need to serve up 2 seperate arrays. one of the parents and one of the children.
Try using the include method, like so:
#parents = Parent.where(:parent_id => 3).include(:children)
Now rails will have fetched the associated children and you should be able to loop over #parents and access their children without additional queries, like so:
#parents.each do |p|
puts "#{p}'s children: #{p.children}"
end
I have a model, blog_posts which has a field "published_at". I'd like to select the latest two blogs from that model to display on my homepage. Not sure how to structure that though.
At the moment I have a work around that takes a slice of the data but it keeps failing when I have nothing in the table, rather than fix this I feel there is probably a better way to retrieve the data.
I need to select the blogs in separate calls, for example
#blog_post.latestpost, #blog_post.secondlatestpost
Is this what you're looking for? :
class BlogPost < Activerecord::Base
def self.latestpost
order("published_at DESC").limit(1).first
end
def self.secondlatestpost
order("published_at DESC").offset(1).limit(1).first
end
end
Use it like this :
BlogPost.secondlatestpost
or
BlogPost.latestpost
Hope this helps.
You could also do:
BlogPost.order(:published_at).last # for the last post
BlogPost.order(:published_at).offset(1).last # for the second to last post
As of Rails 5 you can use BlogPost.second_to_last.
http://api.rubyonrails.org/v5.0/classes/ActiveRecord/FinderMethods.html#method-i-second_to_last
At least since Rails 4.x you can specify how many last records you want. E.g. to fetch last 2 records:
BlogPost.last(2) # BlogPost.last(2).first will return the second last post
The same goes for first(). There are also methods second(), third(), fourth(), fifth(), forty_two(). And starting with Rails 5.x, second_to_last(), third_to_last().
You could also use ActiveRecord
BlogPost.order("published_at DESC").second
Although I think going with offset and limit is the somewhat cleaner and more portable version. Internally second (and third, fourth) use the find_nths method. Documented here:
http://apidock.com/rails/ActiveRecord/FinderMethods/second