Using scopes in activerecord queries - ruby-on-rails-3

I have a scope in user.rb
scope :active, -some logic here-
How can I use this a where query, something like
User.where("users.active is not nil")
Is there a way to use scopes in a where clause?

Of course it is. Just like this:
User.where("users.active is not nil").active

Related

How to prevent using a named_scope from creating n+1 queries

What is the best way to prevent ActiveRecord from making an unnecessary query when referencing a list of models that already been loaded?
class Checklist
has_many :checklist_items
scope :active, where(active: true)
end
class ChecklistItem
belongs_to :checklist
scope :active, where(active: true)
end
#checklists = Checklist.active.includes(:checklist_items).where(checklist_items: {active: true})
# Works fine, does NOT make extra SQL query
#checklists[0].checklist_items
# Makes extra query. How do I prevent this?
#checklists[0].checklist_items.active
What is the best work around for preventing this extra query when using a named_scope?
As soon as you use where, you'll trigger another query. If you think you have all your records in memory, treat the resulting active record relation as an array, not SQL. Use array methods like select instead of where. Perhaps:
#checklists[0].checklist_items.select {|ci| ci.active == true}

Create scopes using instance methods best way

I was wondering what's the best way to make an scope using an instance method to filter records. This is my model:
class Promotion < ActiveRecord::Base
scope :availables, lambda{ all.select{ |obj| obj.is_available? } }
def is_available?
Date.today <= Date.strptime(valid_thru, '%m/%d/%Y')
...more validations here
end
end
The problem here is this scope returns an array instead of an ActiveRecord::Relation and I'm not able to chain other scopes.
Any suggestion guys?
There is no way to accomplish what you want. If you want to apply logic on ruby objects you can no longer return an ActiveRecord::Relation.
The only way to achieve something like this is have the logic on a database level. In that case you could use a class method to achieve what you want like so:
def availables
where('valid_thru => ?', Date.today)
end

Rails ActiveRecord Scope that is the "opposite" of another scope, or is users that "lack" a property

I have a model for user.rb, in which I define a scope for admins, which is users that have the role of admin through a permissions table.
has_many :permissions
has_many :roles, :through => :permissions
The scope works like this:
scope :admins, joins(:permissions).merge(Permission.admin_permissions)
I'd also like to make a scope called non-admins or something like that, which is all users that do NOT have the admin role.
What's the easiest way to do this?
If you want to have an inverted SQL query, you will have to do it yourself manually. There is no built-in ActiveRecord solution.
scope :admins, joins(:permissions).merge(Permission.where("permissions.admin = true"))
scope :non_admins, joins(:permissions).merge(Permission.where("permissions.admin = false"))
If there are a lot of scopes or they are complex, consider excluding them by id:
User.where("id not in (?)", User.admins.pluck(:id))
# or if you are already using admin records
admins = User.admins
User.where("id not in (?)", admins.map(&:id))
Depending on number of rows and complexity of the original query, this could be slower or faster than the previous way.
An easy way, which would not be performant for a lot of users:
admin_user_ids = User.admins.map(&:id)
non_admin_users = User.all.reject { |u| admin_user_ids.include?(u.id) }

ActiveRecord how to know if an instance model is into one of the class scopes?

I have a scope defined in my ActiveRecord class, let's say:
class Book < ActiveRecord::Base
scope :old, where( "published_at < ?", 1.year.ago )
end
I would like to ask to any instance of this class something like this:
book.old?
Is there any way to do this without duplicating the where definition?
Run another query on the database, using your scope:
Book.old.exists?(book.id)
If you want to re-use this in multiple places, it would be better to implement a method:
def old?
Book.old.exists?(id)
end
book.old?

How do you name order scope of the Rails3?

I have naming question.
Suppose if we have these kind of scopes in model of Rails3 application,
scope :order_by_date, order("created_at asc")
scope :order_by_date_desc, order("created_at desc")
The name of scope is too long and explanatory as scope.
scope :ordered, order("created_at asc")
But if we define as above, it's difficult to distinguish between asc or desc.
So how do you use scope such a case? or do you use scope?
Does anyone have good idea?
Thanks.
Well...
Model.ascending_order
Model.descending_order