I am new to Ruby on Rails and am having trouble with a simple where with a model.
When I try to do Test #1 the results are out of order. New items get pushed to the bottom no matter what.
def index
#user = User.where(:status => false).order(last_name: :desc).all
end
If I enter this into rails console it doesn't work also but if I remove the all it works perfectly in rails console but doesn't work in the UsersController.
What is the proper way to do a where clause with an order? Thanks for your help!
UPDATE:
I have updated the code to the following but the results are still out of order:
def index
#user = User.where(status: false).order('last_name DESC')
end
You should use order('last_name DESC') instead of order(last_name: :desc).
order(last_name: :desc) will produce sql like (That's why your order doesn't work):
ORDER BY '---\\n:last_name: :desc\\n'
order('last_name DESC') will produce sql right:
ORDER BY last_name DESC
Rails 4
def index
#user = User.where(status: false).order('last_name DESC')
end
Related
I'm making a Ruby App for reviewing movies. In my movie index view I have a drop down menu which will select the name of the category to sort by and the movie controller contains the following code to display only movies of that genre:
#category_id = Category.find_by(name: params[:category]).id
#movies = Movie.where(:category_id => #category_id).("created_at DESC")
Movies belong to a category in the database.
Now for some reason I get the following error:
NoMethodError in MoviesController#index
undefined method `call' for # Did you mean? caller
Whenever I try to sort the movies. This is thrown on the second line of the code above. This worked before I cleared my database, (the categories are still intact) so it might have something to do with it.
I think the bug is the .("created_at DESC"), I think you want: order(created_at: :desc)
What JP Silvashy said.
Also, you can do:
#category = Category.find_by(name: params[:category])
#movies = Movie.where(category: #category).order(created_at: :desc)
This assumes Movie belongs_to :category.
Or you could just do (unless you're going to use #category somewhere else):
#movies = Movie.where(category: Category.find_by(name: params[:category])).order(created_at: :desc)
In my app i use rails 4.
And i need to fetch as i do now data, but all except one params[:id], now i have such code:
#vip_cars = Car.order(created_at: :desc, is_vip: :desc).limit(100).sample(4)
and i try something like:
#vip_cars = Car.order(created_at: :desc, is_vip: :desc).not(id: params[:id]).limit(100).sample(4)
but it didn't work. What i do wrong? how to fetch data with order, limit, sample and not in rails 4?
You should write as
Car.order(created_at: :desc, is_vip: :desc)
.where.not(id: params[:id])
.limit(100).sample(4)
Read #not
Returns a new relation expressing WHERE + NOT condition according to the conditions in the arguments.
Remember #not always work in conjunction with #where.
I am kind of new at rails, currently using version 3.23 and I am trying to enable 'sort' on two columns in my table. I managed to create the links on these column headers and actually got one column working/sorting!But couldnt achieve the same result when I modified my code in the movie controller rb, my code can only work for one column! is:
def index
#movies = Movie.all.sort_by { |movie| movie.title }
end
Works perfectly, but when I combine another parameter i.e. release date I get an error!
def index
#movies = Movie.all.sort_by { |movie| movie.title } then { |release date| release.date}
end
Can someone please help me resolve this issue? I have researched it on google but I've gotten nothing conclusive!. Any help will be most appreciated.
Assuming that you have to sort on title and release_date fields in movies table.
You can perform the sorting at database level itself as below:
In Rails 4.x:
Below will sort all the movie records with title and release_date in ascending order(as default).
def index
#movies = Movie.order(:title, :release_date)
end
If you want to change the order, you can specify as asc or desc as:
def index
#movies = Movie.order(title: :asc, release_date: :desc)
end
In Rails 3.x:
def index
#movies = Movie.all(:order => "title ASC, release_date ASC")
end
If you want to change the order, you can specify as DESC in the above case.
You can order your listing by this
def index
#movies = Movie.order(title: :asc, release_data: :desc)
end
How do I select a single random record for each user, but order the Array by the latest record pr. user.
If Foo uploads a new painting, I would like to select a single random record from foo. This way a user that uploads 10 paintings won't monopolize all the space on the front page, but still get a slot on the top of the page.
This is how I did it with Rails 2.x running on MySQL.
#paintings = Painting.all.reverse
first_paintings = []
#paintings.group_by(&:user_id).each do |user_id, paintings|
first_paintings << paintings[rand(paintings.size-1)]
end
#paintings = (first_paintings + (Painting.all - first_paintings).reverse).paginate(:per_page => 9, :page => params[:page])
The example above generates a lot of SQL query's and is properly badly optimized. How would you pull this off with Rails 3.1 running on PostgreSQL? I have 7000 records..
#paintings = Painting.all.reverse = #paintings = Painting.order("id desc")
If you really want to reverse the order of the the paintings result set I would set up a scope then just use that
Something like
class Painting < ActiveRecord::Base
scope :reversed, order("id desc")
end
Then you can use Painting.reversed anywhere you need it
You have definitely set up a belongs_to association in your Painting model, so I would do:
# painting.rb
default_scope order('id DESC')
# paintings_controller.rb
first_paintings = User.includes(:paintings).collect do |user|
user.paintings.sample
end
#paintings = (first_paintings + Painting.where('id NOT IN (?)', first_paintings)).paginate(:per_page => 9, :page => params[:page])
I think this solution results in the fewest SQL queries, and is very readable. Not tested, but I hope you got the idea.
You could use the dynamic finders:
Painting.order("id desc").find_by_user_id!(user.id)
This is assuming your Paintings table contains a user_id column or some other way to associate users to paintings which it appears you have covered since you're calling user_id in your initial code. This isn't random but using find_all_by_user_id would allow you to call .reverse on the array if you still wanted and find a random painting.
I feel this should be very simple but my brain is short-circuiting on it. If I have an object representing the current user, and want to query for all users except the current user, how can I do this, taking into account that the current user can sometimes be nil?
This is what I am doing right now:
def index
#users = User.all
#users.delete current_user
end
What I don't like is that I am doing post-processing on the query result. Besides feeling a little wrong, I don't think this will work nicely if I convert the query over to be run with will_paginate. Any suggestions for how to do this with a query? Thanks.
It is possible to do the following in Rails 4 and up:
User.where.not(id: id)
You can wrap it in a nice scope.
scope :all_except, ->(user) { where.not(id: user) }
#users = User.all_except(current_user)
Or use a class method if you prefer:
def self.all_except(user)
where.not(id: user)
end
Both methods will return an AR relation object. This means you can chain method calls:
#users = User.all_except(current_user).paginate
You can exclude any number of users because where() also accepts an array.
#users = User.all_except([1,2,3])
For example:
#users = User.all_except(User.unverified)
And even through other associations:
class Post < ActiveRecord::Base
has_many :comments
has_many :commenters, -> { uniq }, through: :comments
end
#commenters = #post.commenters.all_except(#post.author)
See where.not() in the API Docs.
#users = (current_user.blank? ? User.all : User.find(:all, :conditions => ["id != ?", current_user.id]))
You can also create named_scope, e.g. in your model:
named_scope :without_user, lambda{|user| user ? {:conditions => ["id != ?", user.id]} : {} }
and in controller:
def index
#users = User.without_user(current_user).paginate
end
This scope will return all users when called with nil and all users except given in param in other case. The advantage of this solution is that you are free to chain this call with other named scopes or will_paginate paginate method.
Here is a shorter version:
User.all :conditions => (current_user ? ["id != ?", current_user.id] : [])
One note on GhandaL's answer - at least in Rails 3, it's worth modifying to
scope :without_user, lambda{|user| user ? {:conditions => ["users.id != ?", user.id]} : {} }
(the primary change here is from 'id != ...' to 'users.id !=...'; also scope instead of named_scope for Rails 3)
The original version works fine when simply scoping the Users table. When applying the scope to an association (e.g. team.members.without_user(current_user).... ), this change was required to clarify which table we're using for the id comparison. I saw a SQL error (using SQLite) without it.
Apologies for the separate answer...i don't yet have the reputation to comment directly on GhandaL's answer.
Very easy solution I used
#users = User.all.where("id != ?", current_user.id)
User.all.where("id NOT IN(?)", current_user.id) will through exception
undefined method where for #<Array:0x0000000aef08f8>
User.where("id NOT IN (?)", current_user.id)
Another easy way you could do it:
#users = User.all.where("id NOT IN(?)", current_user.id)
an array would be more helpful
arrayID[0]=1
arrayID[1]=3
User.where.not(id: arrayID)
User.where(:id.ne=> current_user.id)
ActiveRecord::QueryMethods#excluding (Rails 7+)
Starting from Rails 7, there is a new method ActiveRecord::QueryMethods#excluding.
A quote right from the official Rails docs:
excluding(*records)
Excludes the specified record (or collection of records) from the resulting relation. For example:
Post.excluding(post)
# SELECT "posts".* FROM "posts" WHERE "posts"."id" != 1
Post.excluding(post_one, post_two)
# SELECT "posts".* FROM "posts" WHERE "posts"."id" NOT IN (1, 2)
This can also be called on associations. As with the above example, either a single record of collection thereof may be specified:
post = Post.find(1)
comment = Comment.find(2)
post.comments.excluding(comment)
# SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = 1 AND "comments"."id" != 2
This is short-hand for .where.not(id: post.id) and .where.not(id: [post_one.id, post_two.id]).
An ArgumentError will be raised if either no records are specified, or if any of the records in the collection (if a collection is passed in) are not instances of the same model that the relation is scoping.
Also aliased as: without
Sources:
Official docs - ActiveRecord::QueryMethods#excluding
PR - Add #excluding to ActiveRecord::Relation to exclude a record (or collection of records) from the resulting relation.
What's Cooking in Rails 7?
What you are doing is deleting the current_user from the #users Array. This won't work since there isn't a delete method for arrays. What you probably want to do is this
def index
#users = User.all
#users - [current_user]
end
This will return a copy of the #users array, but with the current_user object removed (it it was contained in the array in the first place.
Note: This may not work if array subtraction is based on exact matches of objects and not the content. But it worked with strings when I tried it. Remember to enclose current_user in [] to force it into an Array.