Result check with activerecord - ruby-on-rails

When we are checking one active record result is empty or not, what will be
way which have more performance.
pc_count = Property.select("id").where('property_category_id = ?', 5).limit(1)
if pc_count.blank?
#
end
if pc_count[0]
#
end
In two ways i have tried this pc_count.blank? or pc_count[0], because i heard that blank will take extra query, but when i tried that in console i couldn't see that any extra call

Try exists
which will be like.
Person.exists?(5)
Person.exists?('5')
Person.exists?(:name => "David")
Person.exists?(['name LIKE ?', "%#{query}%"])
Person.exists?
refer: http://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-exists-3F

No, both your versions do not produce another query.
It depends what you are doing with pc_count:
1.) You are using that id somewhere later, then use either of your methods (i prefer .blank?)
2.) You only need this for the this check. Then I would do
Property.select("id").where('property_category_id = ?', 5).limit(1).count
because there will be no model created and you can just test count == 0

Related

OR operator inside a Where Active Record Query

So inside a Where Active Record(AR) query you can do:
game_stickers.where('stickers.name != ?', 'Ban')
But how can you test matches against multiple strings with an OR operator without doing something like:
game_stickers.where('stickers.name != ? OR stickers.name != ?', 'Ban', 'Closed')
or without reverting to something like [see note below]:
game_stickers.where.not(stickers.name: ['Ban','Closed','Block'])
NOTE:
The reason I do not want to go with the last alternative is because I'm using some joins and references in my queries that (as far as I can see) do not play nicely with this option. The context code goes something like:
game_stickers_and_stickers = game_stickers.includes(:sticker)
game_stickers_and_stickers.where('stickers.name = ?', 'Ban').references(:stickers).where(placement_side: side)
Maybe a you can advise on the optimal way to do this query.
Note: it seems to me you want an AND between those conditions, not an OR. Think about it. Anyway, try this one
game_stickers_and_stickers = game_stickers.includes(:sticker)
game_stickers_and_stickers.where.not(stickers: {name: ['Ban','Closed','Block']}).where(placement_side: side)
that condition fragment should be converted to the SQL
WHERE stickers.name NOT IN ('Ban', 'Closed', 'Block')

Rails Query Unique Items

I have a search bar which works fine but it produces a duplicate every time it shows the correct result.
if params[:nav_search]
#art = Art.where(["style_number LIKE ? OR name LIKE ?", "%#{params[:nav_search]}%", "%#{params[:nav_search]}%"]).page(params[:page]).per_page(18)
end
Any clue where I'm going wrong?
Try to the following
#art = Art.where(["style_number LIKE ? OR name LIKE ?", "%#{params[:nav_search]}%", "%#{params[:nav_search]}%"]).distinct.page(params[:page]).per_page(18)
To retrieve objects from the database, Active Record provides several finder methods. Each finder method allows you to pass arguments into it to perform certain queries on your database without writing raw SQL.
You can see this Rails Guide for very well understand
include .uniq
try this,
if params[:nav_search]
#art = Art.where(["style_number LIKE ? OR name LIKE ?", "%#{params[:nav_search]}%", "%#{params[:nav_search]}%"]).uniq.page(params[:page]).per_page(18)
end
Use uniq or distinct to avoid duplicate records. In your case, you should use distinct:
if params[:nav_search]
#art = Art.where(["style_number LIKE ? OR name LIKE ?", "%#{params[:nav_search]}%", "%#{params[:nav_search]}%"]).distinct.page(params[:page]).per_page(18)
end

How do i not include latest record but all record from an object in rails?

For example if i want to pull all #posts using #posts.all but i dont want to include the very last or latest record from that?
here is what i am trying to do,
#posts = Post.all(Without the very very latest record that was created.)
Basically all record but not the very last record.
I think it is not worth it to try to generate a SQL query that excludes the very last element. Especially a subquery might be slower than just loading all records into an Array and than excluding the last:
#posts = Post.all[0..-2]
Your other example from the comments would look like this:
#contact_prices = #contact.retail_prices.all.order("created_at DESC").load[0..-2]
Another option (depending on the order of your relation) might be to use offset:
#contact_prices = #contact.retail_prices.order("created_at DESC").offset(1)
This is the most direct way I think of doing what you're trying to do:
Post.limit(Post.count - 1)
If you want your query to allow pagination or other LIMIT queries, you could try something like
Post.where("id < ?", Post.last.id)
Lots of answers that will do the trick, but throwing out an additional option:
#posts = Post.where("id != ?", Post.last.id)
One line AR:
Post.where.not(id: Post.last&.id)

Rails find by first attribute or second attribute

I currently have the following in my controller to find the device:
Device.find_by_token(params[:token])
Replacing token with unique_id.
So the new query would be:
Device.find_by_unique_id(params[:unique_id])
For some of older requests, unique_id is not being passed in params and device won't be found.
How can I do something like:
Device.find_by_token_or_unique_id(params[:token], params[:unique_id])
or course this doesn't exist.
Also, I don't want to do:
if params[:token]
Device.find_by_unique_id(params[:unique_id])
else
Device.find_by_token(params[:token])
end
Thanks in advance.
I think this is what you are looking for:
Devise.where("token = ? OR unique_id = ?", params[:token], params[:unique_id]).first
Keeping in mind the previous answer could potentially return you 2 items, you could do this alternative:
user = Device.where(unique_id: params[:unique_id]).first
user ||= Device.where(token: params[:token]).first
Or you could implement Arel Helpers and be able to actual build it as a or query.
https://github.com/camertron/arel-helpers
I prefer to using Arel as it makes your code no longer contain ANY SQL.

Empty Scope with Ruby on Rails

Following Problem:
I need something like an empty scope. Which means that this scope is emtpy, but responds to all methods a scope usually responds to.
I'm currently using a little dirty hack. I simply supply "1=0" as conditions. I find this realy ugly, since it hits the database. Simply returning an empty array won't work, since the result must respond to the scoped methods.
Is there a better existing solution for this or will I need to code this myself?
Maybe some example code could help explain what i need:
class User < ActiveRecord::Base
named_scope :admins, :conditions => {:admin => true }
named_scope :none_dirty, :conditions => "1=0" # this scope is always empty
def none_broken
[]
end
def self.sum_score # okay, a bit simple, but a method like this should work!
total = 0
self.all.each do |user|
total += user.score
end
return total
end
end
User.admin.sum_score # the score i want to know
User.none_drity.sum_score # works, but hits the db
User.none_broken.sum_score # ...error, since it doesn't respond to sum_score
Rails 4 introduces the none scope.
It is to be used in instances where you have a method which returns a relation, but there is a condition in which you do not want the database to be queried.
If you want a scope to return an unaltered scope use all:
No longer will a call to Model.all execute a query immediately and return an array of records. In Rails 4, calls to Model.all is equivalent to now deprecated Model.scoped. This means that more relations can be chained to Model.all and the result will be lazily evaluated.
User.where('false')
returns an ActiveRecord::Relation with zero elements, that is a chain-able scope that won't hit the database until you actually try to access one of its elements. This is similar to PhilT's solution with ('1=0') but a little more elegant.
Sorry User.scoped is not what you want. As commented this returns everything. Should have paid more attention to the question.
I've seen where('1 = 0') suggested before and Rails should probably cache it as well.
Also, where('1 = 0') won't hit the database until you do .all, .each, or one of the calculations methods.
I thing you need User.scoped({})
How about User.where(id: nil) ?
Or User.where(_id: nil) for mongoid.
The thing you are looking for does not exist. You could implement something like this by monky patching the find method. Yet, this would be an overkill, so I recomend keeping this unless it's performance critical.
Looking at your example code indicates you may not know about aggregated queries in SQL which are exposed as calculations methods in Rails:
User.sum(:score) will give you the sum of all users' scores
Take a look at Rails Guides for more info:
http://guides.rubyonrails.org/active_record_querying.html#sum

Resources