Rails scope for the current tenant - ruby-on-rails

I have a multi tenant Rails app.
I use this line of code in each of the models:
default_scope { where(tenant_id: Tenant.current_id) }
I have a model called worequest and it contains an integer column called request_closed. I would like each tenant to define which statuscode is closed for them.
After the default_scope statement, I'm trying to set a scope for requests that are not closed.
I've tried the following and they don't work:
scope :closed, where(:statuscode_id => Tenant.current.request_closed)
scope :closed, where(:statuscode_id => current_tenant.request_closed)
scope :closed, where(:statuscode_id => Tenant.request_closed)
scope :closed, where(:statuscode_id => Tenant.current_id.request_closed)
Is it possible to do what I want?
Thanks for the help!

Seeing as request_closed is an attribute on Tenant, you'll need to retrieve your current tenant, using your current_id value, and then call it on that.
Tenant.find(Tenant.current_id).request_closed

Related

How to add condition for all where query for an ActiveRecordModel?

I have a user table in my rails application and the application uses many where conditions for this model throughout the application in many controller methods.
Now i have to add an extra attribute for the where condition.
is there a way to do the following and how? instead of adding the extra attribute to all the where condition used in the entire application can i write a custom where to the user model so the condition will be pre-added to the where in entire application for the user model.
i found out the source for the where
def where(opts = :chain, *rest)
if :chain == opts
WhereChain.new(spawn)
elsif opts.blank?
self
else
spawn.where!(opts, *rest)
end
end
my where condition in the controller methods now:
User.where(:status => true, :country => "IN")
this condition and similar conditions are used in many methods in application and i want to get the user who has not :deactivated.
i can make changes to all where condition like
User.where(:status => true, :country => "IN", :deactivated => false)
instead i thought of writing a custom where that precheck :deactivated => false
Default Scope:
class User < ActiveRecord::Base
default_scope -> { where(deactivated: false) }
end
You can use default_scope.
Now, whenever you query User, automatically the default scope query will get appended.
For more details on default_scope, please refer:
https://api.rubyonrails.org/classes/ActiveRecord/Scoping/Default/ClassMethods.html#method-i-default_scope
If there are usecases that prevent you from using default_scope, then you can use custom scopes or unscope the default scope.
Unscoping:
You can unscope in Project model if you want to remove the default scope.
belongs_to :user, ->{ unscope(where: :deactivated) }
Or you can fetch all user and then unscope
project.users.unscoped
Custom Scope:
class User < ActiveRecord::Base
scope :deactivated, ->(deactivated = false) { where(deactivated: deactivated) }
end
Now, to make use of that scope, you can query like this:
User.deactivated.where(:status => true, :country => "IN")
For reference:
https://api.rubyonrails.org/classes/ActiveRecord/Scoping/Named/ClassMethods.html#method-i-scope

Rails3 Active Admin: How to display only Open status records when first click on Shipments tag?

I'm using ActiveAdmin. I have a list of Shipments with status (as a string) of Open and Closed. When the user clicks on the Shipments tab, I want to display only the Open shipments. How can I do that? Of course, the user could later choose to see the Closed shipments by using the filter. But I want the default to initially only show the Open shipments.
Probably best way will be to create scopes in model. AA automatically gets your scopes and creates tabs above table in index view. Remember to add scopes in app/admin/your-resource-name.rb file.
#app/models/shipments.rb
scope :opened, where(:status => "Open")
scope :closed, where(:status => "Closed")
... and add scopes to resource file
#app/admin/shipments.rb
scope :opened
scope :closed
I don't have time to test, but it should work.
ASCIIcast with simple scope: http://asciicasts.com/episodes/284-active-admin
scopes in the model:
#app/models/shipments.rb
scope :opened, where(:status => "Open")
scope :closed, where(:status => "Closed")
scopes in the activeadmin resource, one marked as default:
#app/admin/shipments.rb
scope :opened, :default => :true
scope :closed

How do I ignore entries based on boolean fields using default_scope

Simple question. Currently, for Post model, this is my setup for the default scope
default_scope :order => 'posts.created_at ASC'
How can I augment this to only have those where :draft => false
Also, how can I make a non-default scope to return those where :draft => true?
Thanks!
Don't use default_scope in this case. Use these regular scopes:
scope :drafts, where(:draft => true)
scope :published, where(:draft => false)
If you really want to use default_scope (which I don't recommend as it limits you and makes you have to get around it later), you can do it like this:
default_scope order('posts.created_at').where(:draft => false)
and to get drafts later:
#drafts = Post.unscoped.where(:draft => true)
But again, if you're using default_scope it means that you want it to ALWAYS use those conditions, and by using unscoped you're basically telling ActiveRecord NOT to do something that you explicitly told it to. To me, this is a hack.

Mongoid named scope comparing two time fields in the same document

I need to create a named scope in Mongoid that compares two Time fields within the same document. Such as
scope :foo, :where => {:updated_at.gt => :checked_at}
This obviously won't work as it treats :checked_at as a symbol, not the actual field. Any suggestions on how this can be done?
Update 1
Here is my model where I have this scope declared, with a lot of extra code stripped out.
class User
include Mongoid::Document
include Mongoid::Paranoia
include Mongoid::Timestamps
field :checked_at, :type => Time
scope :unresolved, :where => { :updated_at.gt => self.checked_at }
end
This gives me the following error:
'<class:User>': undefined method 'checked_at' for User:Class (NoMethodError)
As far as I know, mongodb doesn't support queries against dynamic values.
But you could use a javascript function:
scope :unresolved, :where => 'this.updated_at >= this.checked_at'
To speed this up you could add an attribute like "is_unresolved" which will be set to true on update when this condition is matched ( and index that ).
scope :foo, :where => {:updated_at.gt => self.checked_at}
For example, this will work:
scope :foo, where(:start_date.lte=>Date.today.midnight)
Not sure if you'll like this method, it's not the best, but it should work.
class User
include Mongoid::Document
include Mongoid::Paranoia
include Mongoid::Timestamps
field :checked_at, :type => Time
scope :unresolved, lambda{ |user| where(:updated_at.gt => user.checked_at) }
end
You call it with User.unresolved(my_user_object)
It seems now after rereading your post that this probably won't do what you want. If this is true, then you will probably need to use MapReduce or possibly Baju's method (have not tested it)

Custom getters in Ruby on Rails

I have a MailingList model that has_may :people
For most of my application, I only want to get people that are active
So #mailing_list.people should only return people that are active
In my model, I can't do
def people
self.people.find_all{ |p| !p.activated_at.nil? }
end
because that keeps calling itself. What is the ruby/rails way to automatically filter the people. Another possible issue is that I think self.people returns an array of active record objects where self.people.find_all... will return an array. This will cause some of my code to break. It's easy fixes but is there a way to return active record objects? It would be nice to have the option.
Thanks!
This is a perfect example for a named scope:
class Person < ActiveRecord::Base
named_scope :active, :conditions => 'activated_at is not null'
end
Then just call it:
# equivalent to Person.find(:all, :conditions => 'activated_at is not null')
#active_people = Person.active
You can also filter at the association level.
has_many :people, :conditions => {:activated => true}
You can used the standard find method or a dynamic finder. Your find might read as follows:
people.find(:all, :conditions => "activated_at = nil")
OR
people.find_all(:conditions => "activated_at = nil")
A dynamic version of this might read as:
people.find_by_activated_at(nil)

Resources