Getting the id with a rails find with :select - ruby-on-rails

I have this rails find that i need to get the id as well but if i put the id in the :select wont it effect the query and is there another way to get the id
#past_requests = Request.find_all_by_artist(name, :conditions => ["showdate < ?", Time.now], :select => "distinct venue, showdate")

#past_requests = Request.find_all_by_artist(name, :group => "venue, showdate")
code long for view. i'm remove your condition. sorry about this. Hope it'll helpful for you. :)

To be fair in cases where distinct returns a single row out of maybe 5 duplicates who's to say which id out of those 5 should be displayed in your result? I'm afraid what you are asking for is not practical. Maybe you misunderstand what distinct is used for ? Give us more info pls.

Related

Active Record Query used "NOT IN" [duplicate]

I'm hoping there is a easy solution that doesn't involve find_by_sql, if not then I guess that will have to work.
I found this article which references this:
Topic.find(:all, :conditions => { :forum_id => #forums.map(&:id) })
which is the same as
SELECT * FROM topics WHERE forum_id IN (<#forum ids>)
I am wondering if there is a way to do NOT IN with that, like:
SELECT * FROM topics WHERE forum_id NOT IN (<#forum ids>)
Rails 4+:
Article.where.not(title: ['Rails 3', 'Rails 5'])
Rails 3:
Topic.where('id NOT IN (?)', Array.wrap(actions))
Where actions is an array with: [1,2,3,4,5]
FYI, In Rails 4, you can use not syntax:
Article.where.not(title: ['Rails 3', 'Rails 5'])
Using Arel:
topics=Topic.arel_table
Topic.where(topics[:forum_id].not_in(#forum_ids))
or, if preferred:
topics=Topic.arel_table
Topic.where(topics[:forum_id].in(#forum_ids).not)
and since rails 4 on:
topics=Topic.arel_table
Topic.where.not(topics[:forum_id].in(#forum_ids))
Please notice that eventually you do not want the forum_ids to be the ids list, but rather a subquery, if so then you should do something like this before getting the topics:
#forum_ids = Forum.where(/*whatever conditions are desirable*/).select(:id)
in this way you get everything in a single query: something like:
select * from topic
where forum_id in (select id
from forum
where /*whatever conditions are desirable*/)
Also notice that eventually you do not want to do this, but rather a join - what might be more efficient.
You can try something like:
Topic.find(:all, :conditions => ['forum_id not in (?)', #forums.map(&:id)])
You might need to do #forums.map(&:id).join(','). I can't remember if Rails will the argument into a CSV list if it is enumerable.
You could also do this:
# in topic.rb
named_scope :not_in_forums, lambda { |forums| { :conditions => ['forum_id not in (?)', forums.select(&:id).join(',')] }
# in your controller
Topic.not_in_forums(#forums)
To expand on #Trung Lê answer, in Rails 4 you can do the following:
Topic.where.not(forum_id:#forums.map(&:id))
And you could take it a step further.
If you need to first filter for only published Topics and then filter out the ids you don't want, you could do this:
Topic.where(published:true).where.not(forum_id:#forums.map(&:id))
Rails 4 makes it so much easier!
The accepted solution fails if #forums is empty. To workaround this I had to do
Topic.find(:all, :conditions => ['forum_id not in (?)', (#forums.empty? ? '' : #forums.map(&:id))])
Or, if using Rails 3+:
Topic.where( 'forum_id not in (?)', (#forums.empty? ? '' : #forums.map(&:id)) ).all
Most of the answers above should suffice you but if you are doing a lot more of such predicate and complex combinations check out Squeel. You will be able to doing something like:
Topic.where{{forum_id.not_in => #forums.map(&:id)}}
Topic.where{forum_id.not_in #forums.map(&:id)}
Topic.where{forum_id << #forums.map(&:id)}
You may want to have a look at the meta_where plugin by Ernie Miller. Your SQL statement:
SELECT * FROM topics WHERE forum_id NOT IN (<#forum ids>)
...could be expressed like this:
Topic.where(:forum_id.nin => #forum_ids)
Ryan Bates of Railscasts created a nice screencast explaining MetaWhere.
Not sure if this is what you're looking for but to my eyes it certainly looks better than an embedded SQL query.
The original post specifically mentions using numeric IDs, but I came here looking for the syntax for doing a NOT IN with an array of strings.
ActiveRecord will handle that nicely for you too:
Thing.where(['state NOT IN (?)', %w{state1 state2}])
Can these forum ids be worked out in a pragmatic way? e.g. can you find these forums somehow - if that is the case you should do something like
Topic.all(:joins => "left join forums on (forums.id = topics.forum_id and some_condition)", :conditions => "forums.id is null")
Which would be more efficient than doing an SQL not in
This way optimizes for readability, but it's not as efficient in terms of database queries:
# Retrieve all topics, then use array subtraction to
# find the ones not in our list
Topic.all - #forums.map(&:id)
You can use sql in your conditions:
Topic.find(:all, :conditions => [ "forum_id NOT IN (?)", #forums.map(&:id)])
Piggybacking off of jonnii:
Topic.find(:all, :conditions => ['forum_id not in (?)', #forums.pluck(:id)])
using pluck rather than mapping over the elements
found via railsconf 2012 10 things you did not know rails could do
When you query a blank array add "<< 0" to the array in the where block so it doesn't return "NULL" and break the query.
Topic.where('id not in (?)',actions << 0)
If actions could be an empty or blank array.
Here is a more complex "not in" query, using a subquery in rails 4 using squeel. Of course very slow compared to the equivalent sql, but hey, it works.
scope :translations_not_in_english, ->(calmapp_version_id, language_iso_code){
join_to_cavs_tls_arr(calmapp_version_id).
joins_to_tl_arr.
where{ tl1.iso_code == 'en' }.
where{ cavtl1.calmapp_version_id == my{calmapp_version_id}}.
where{ dot_key_code << (Translation.
join_to_cavs_tls_arr(calmapp_version_id).
joins_to_tl_arr.
where{ tl1.iso_code == my{language_iso_code} }.
select{ "dot_key_code" }.all)}
}
The first 2 methods in the scope are other scopes which declare the aliases cavtl1 and tl1. << is the not in operator in squeel.
Hope this helps someone.
If someone want to use two or more conditions, you can do that:
your_array = [1,2,3,4]
your_string = "SOMETHING"
YourModel.where('variable1 NOT IN (?) AND variable2=(?)',Array.wrap(your_array),your_string)

trying to walk a tree, always getting no results

I have a n-tier affiliate system which I'm trying to walk so I can get counts and lists of affiliates' sub-affiliates. I have, among other fields, an "id" and "affiliate_id" on each entry.
def find_affiliates_under(affid)
affs=Array.new
Affiliate.find(:all, :conditions => "affiliate_id = " + affid.to_s, :select => :id).each do |a|
affs.concat(find_affiliates_under(a.id))
end
return affs.uniq
end
What am I doing wrong? Would appreciate a pointer from someone with more experience with Ruby
Thanks!
Are you the id's or are you also looking for the nested objects themselves. By placing a select => :id option, you're only going to select the id of each object.
May I recommend taking a look at awesome_nested_set. I think it will achieve what you're trying to do, while saving you some time.

unable to determine row count Ruby-On-Rails

im trying to build a cart in ruby on rails it requires me to show the output like this : You have 3 items in your cart (3 being the number of items in my cart) and im trying to find the number of rows in the table line_items where the cart_id is 5.
#line_items.find(:all, :condition => { :cart_id => "5"}).count
if anyone know how i should write this, please let me know.. Thanks in advance
You can do it the slow way:
YourModelClass.find(:all, :conditions => { :card_id => 5 }).count
or the fast way:
YourModelClass.count(:conditions => { :card_id => 5 })
The fast way simply does a COUNT(*) inside the database, the slow way pulls the whole result set out of the database, turns it into objects, and then counts them.
There's also the modern Rails3+ way:
YourModelClass.where(:card_id => 5).count
That does a select count(*) from t where card_id = 5 inside the database. Don't use this one though:
YourModelClass.count(:card_id => 5)
That will do a select count(card_id = 5) from t and that's nothing at all like what you want.
it should be something alone the line of
LineItem.count(:conditions => {:cart_id => 5})
since i don't really know what's the model name, and the association... hope this helps =)

Association Problem

I am having a problem with an association:
Battalion
:has_many soldiers
Soldiers
:has_many primaries
I need to do this
#bseniorleads=(#user.battalion.soldiers.find(:all, :conditions => ["seniorleader = ?", "Yes"]))
then
#seniorspouse=(#bseniorleads.primaries.find(:all, :conditions => ["relationship = ?", "Spouse"]
This gives me an undefined method for primaries, I assume because the bseniorleads is an array?
Basically I don't know how to do this they right way but I need to be able to query a group from one model that meets a condition and then take that result and find the people from another model that belong to them. Any ideas?
Thanks in advance.
You should be able to do something like this (assuming you only needed the #bseniorleads instance variable in the second query):
#senior_spouse = #user.battalion.soldiers.find(
:all,
:select => 'primaries.*',
:joins => [:primaries],
:conditions => ["seniorleader = ? and primaries.relationship = ?", "Yes", "Spouse"]
)
I haven't checked that yet, but I think it should get you pretty close.
You might want to check out these two rails guides, which certainly helped me better understand ActiveRecord associations and querying:
ActiveRecord Querying
ActiveRecord Associations

Rails, Get a random record when using :group

How do I get a random record when using :group?
#paintings = Painting.all(:group => "user_id", :order => "created_at DESC")
This gives me the latest painting for each user. Now I would like to select a random painting from each user instead of the latest. The order of the paintings should still be the same, so that the user that have been the most active will get his/her random painting displayed first.
painting150 (user1)
painting200 (user2)
painting231 (user3)
Is this possible?
Best regards.
Asbjørn Morell.
This answer is specific to Rails, but since you are using ActiveRecord, I am assuming it should be fine.
unique_paintings = []
#paintings.group_by(&:user_id).each do |user_id, paintings|
unique_paintings << paintings[rand(paintings.size-1)]
end
unique_paintings.sort_by(&:created_at)
The group_by most certainly messes up the created_at sort you did in the query, so I did a sort_by as the last step. You might want to get rid of it in the query since you'll have to do it anyway here.
#painting = #paintings[rand(#paintings.size-1)]
(or paintings.count, dont know the right method yet)
Assuming you have MySQL, you can try:
#paintings = Painting.all(:group => "user_id", :order => "RAND()")
you could do something like this but it will suffer as your number of records grow
#paintings = Painting.find(:all, :order => 'RAND()').map{ |i| i.user_id }.uniq

Resources