I have the following Scope in my Rails app, which is used to fetch active Choices from the database based on the current_user. This works just fine, but if there is no current_user the the code fetches alle the Choices in the database. Here I just want it to fetch nothing.
scope :active, lambda{|user| user ? { :conditions => ["deliverydate = ? and user_id = ?", Date.tomorrow, user.id], :order => 'id DESC'} : {} }
How do I rewrite thee above to return nothing if there is no current_user?
The problem is that I'm using Pusher to push new data to the website, but if the user session expires then all data are pushed instead of nothing.. hopes this makes sense :)
As scopes return an ActiveRecord::Relation instance so it would be more correct to return empty ActiveRecord::Relation object like it's described here.
So, you have to add :none scope which does the trick:
scope :none, limit(0)
and then use it inside your scope like:
scope :active, ->(user = nil) { user ? { :conditions => ["deliverydate = ? and user_id = ?", Date.tomorrow, user.id], :order => 'id DESC'} : none }
scope :active, lambda{|user| user ? { :conditions => ["deliverydate = ? and user_id = ?", Date.tomorrow, user.id], :order => 'id DESC'} : nil }
That is because the empty hash ({}) has no conditions, which basically means return all rows.
Based on the way your code is structured, you could make a condition that is something like :id => -1, :id => nil or 1=0 or something that is always false so it won't return any rows.
(And as was mentioned in the comment below your question, scopes should not return nil since it cannot be chained.)
Related
Looking into passing a variable as value on ActiveRcord query key/column?
login = Login.where("email_address" => "geo#bostj.com","active" => 1).select("id")
=> [#<Login id: 767>]
login = Login.where("email_address" => "geo#bostj.com","active" => 1).select("id").class
=> ActiveRecord::Relation
admin = Admin.where("login_id"=>login).exists?
Heeeelp
I would do:
login = Login.where(email_address: 'geo#bostj.com', active: 1)
Admin.exists?(login_id: login.pluck(:id))
You can write as
login_ids = Login.where("email_address" => "geo#bostj.com","active" => 1).pluck(:id)
Admin.where("login_id in (?)", login_ids).blank?
blank?
Returns true if relation is blank.
Admin.where("login_id in (?)", login_ids) gives back us ActiveRecord::Relation object, so I think we can use #blank? method.
It should be
admin = Admin.where("login_id" => login.first.id).exists?
Okay, at the moment I have the following in my model:
has_many :current_monitorings, :class_name => "Monitoring",
:conditions => proc { [ 'monitorings.created_at > ?', Time.now.midnight ] }
I want to add a condition to this that checks if the outlet is_active attribute is set to false. I tried doing it like this:
has_many :current_monitorings, :class_name => "Monitoring",
:conditions => proc { [ 'monitorings.created_at > ? AND outlet.is_active = ?', Time.now.midnight, 'false' ] }
However, this doesn't work. I'm probably being stupid, but any help is greatly appreciated!
In your sql, outlet.is_active should be outlets.is_active. Assuming is_active is a boolean field, just pass false and not "false":
Try this:
has_many :monitorings
def current_monitorings
monitorings.joins(:outlets).where(
'monitorings.created_at > ? AND outlets.is_active = ?',
Time.now.midnight,
false
)
end
Can someone provide an example on how to use
scope
and parameters?
For example:
class Permission < ActiveRecord::Base
scope :default_permissions, :conditions => { :is_default => true }
end
I have this code that returns the default_permissions and I want to convert it to return the default permissions for a given user (user_id)
Thanks
new syntax (ruby 1.9+), that will prevent errors even if you don't supply the user -
scope :default_permissions_for, ->(user = nil) { ... }
Use lambda scopes:
scope :default_permissions_for, lambda{|user| { :conditions => { :user_id => user.id, :is_default => true } }
Be careful because not passing a parameter to a lambda when it expects one will raise an exception.
named_scope :all_public, lambda { |users|
{ :conditions => ["visibility = ? || (visibility = ? && user_id = ?)", Shared::PUBLIC, Shared::PRIVATE, users] }
}
That works nice for one user, but is there a way to modify it to work where users is an array of user ids?
Something like this and then just pass a single element array for the single ID case
named_scope :all_public, lambda { |users|
{ :conditions => ["visibility = ? OR (visibility = ? AND user_id IN (?))", Shared::PUBLIC, Shared::PRIVATE, users.join(',')] }
}
I'm used to Django where you can run multiple filter methods on querysets, ie Item.all.filter(foo="bar").filter(something="else").
The however this is not so easy to do in Rails. Item.find(:all, :conditions => ["foo = :foo", { :foo = bar }]) returns an array meaning this will not work:
Item.find(:all, :conditions => ["foo = :foo", { :foo = 'bar' }]).find(:all, :conditions => ["something = :something", { :something = 'else' }])
So I figured the best way to "stack" filters is to modify the conditions array and then run the query.
So I came up with this function:
def combine(array1,array2)
conditions = []
conditions[0] = (array1[0]+" AND "+array2[0]).to_s
conditions[1] = {}
conditions[1].merge!(array1[1])
conditions[1].merge!(array2[1])
return conditions
end
Usage:
array1 = ["foo = :foo", { :foo = 'bar' }]
array2 = ["something = :something", { :something = 'else' }]
conditions = combine(array1,array2)
items = Item.find(:all, :conditions => conditions)
This has worked pretty well. However I want to be able to combine an arbitrary number of arrays, or basically shorthand for writing:
conditions = combine(combine(array1,array2),array3)
Can anyone help with this? Thanks in advance.
What you want are named scopes:
class Item < ActiveRecord::Base
named_scope :by_author, lambda {|author| {:conditions => {:author_id => author.id}}}
named_scope :since, lambda {|timestamp| {:conditions => {:created_at => (timestamp .. Time.now.utc)}}}
named_scope :archived, :conditions => "archived_at IS NOT NULL"
named_scope :active, :conditions => {:archived_at => nil}
end
In your controllers, use like this:
class ItemsController < ApplicationController
def index
#items = Item.by_author(current_user).since(2.weeks.ago)
#items = params[:archived] == "1" ? #items.archived : #items.active
end
end
The returned object is a proxy and the SQL query will not be run until you actually start doing something real with the collection, such as iterating (for display) or when you call Enumerable methods on the proxy.
I wouldn't do it like you proposed.
Since find return an array, you can use array methods to filter it, on example:
Item.find(:all).select {|i| i.foo == bar }.select {|i| i.whatever > 23 }...
You can also achive what you want with named scopes.
You can take a look at Searchlogic. It makes it easier to use conditions on
ActiveRecord sets, and even on Arrays.
Hope it helps.
You can (or at least used to be able to) filter like so in Rails:
find(:all, :conditions => { :foo => 'foo', :bar => 'bar' })
where :foo and :bar are field names in the active record. Seems like all you need to do is pass in a hash of :field_name => value pairs.