Rails: Getting an ActiveRecord collection instead of Array - ruby-on-rails

I have a Shop model which has many users:
Shop.rb
def active_users
users.where(status: "active").reverse
end
Currently, when I call some_shop.active_users, I get an array of user objects. But is it possible to instead get an ActiveRecord collection of Users?

It's lazy binding. It'll be an array when you access it.
Try it by calling active_users.to_a

Related

Prevent ActiveRecord Relation converting to Array

UPDATE:
How do I add a virtual attribute to a model and preserve the active record relation.
I tried the below, but .each returns an array, not active record. What other method can I use?
My set_listable_for method is converting an activerecord relation into an array. I want to preserve the ActiveRecord Relation.
At runtime, I added an attr_access to an active record model.
def add_listable_attribute_to(*relation)
relation.each do |rel|
rel[1].first.class.class_eval do
attr_accessor :listable
end
end
end
Then I used this method to set the value of the attribute to the same value for all records....
def set_listable_for(relation, object)
relation.each do |record|
record.listable = object
end
end
However, my ActiveRecord relation gets converted to an Array afterwords.
How to I preserve the Active Record relation, as I don't want an array. Since I continue to use it here and continue to scope and query on it...
def union_scope(*relation)
add_listable_attribute_to(*relation)
listable = relation.first[0]
combined = set_listable_for(relation.first[1], listable)
relation.drop(1).each do |relation_set|
listable = relation[0]
set_listable_for(relation_set[1], listable)
combined = combined.or(relation_set[1])
end
combined
end
Thank you
The .each call executes the query and iterates over the result. It wouldn't be a problem if this happens in the controller after scoping and pagination, but if it gets called before scoping and pagination, the whole model dataset will be loaded which isn't good.
To avoid that, you'll need to set up the listable as late as possible after data is retrieved from the database. I can see three approaches to handle this:
Use a decorator to wrap instances of your relation after it is loaded into the controller or view. This is simpler to understand but pulls the functionality out of the model layer.
Set listable in an after_initialize callback. This keeps the functionality in the model layer, but adds a lot of complexity.
Ensure that you only call set_listable_for in the controller after scoping. Variant of #1.
By adding an 'AS' Statement in Select, I was able to return an ActiveRecord model. Only issue is that when I call .count, I need to use .count(:all), or .count(:id), to prevent errors.
def union_scope(*relation)
listable = relation.first[0]
scope = relation.first[1]
combined = scope.select("#{scope.table_name}.*, \'#{listable.class.name}\' as listable")
relation.drop(1).each do |relation_set|
listable = relation_set[0]
scope = relation_set[1].select("#{scope.table_name}.*, \'#{listable.class.name}\' as listable")
combined = combined.or(scope)
end
combined
end

Using method in a where clause Rails Ruby Active Record

I wondering if it is posible to use a model instance method as a where clause query. I mean. I have a model School with a method defined
class School < ActiveRecord::Base
def my_method
users.where(blablabla).present?
end
end
Is it posible to get something like:
School.all.where(my_method: true)
I know that I can do something like:
School.all.map{|x| x if x.my_method}
But this way has a huge penalization in performance compared to where query. Furthermore, the return of what I'm searching is an ActiveRecord Relation and map returns an array.
UPDATE:
Also there is another way to do it like:
School.all.joins(:users).where("users.attribute = something")
But this do not fit exactly what I want for several reasons.
Thanks in advance
I don't really know the relations between your models.
but where clause gets a hash of key - value.
So you can for example return the ID's of the users in a some kind of a hash and then use it.
def my_method
{user_id: users.where(blablabla).ids}
end
and use it:
School.all.where(my_method)

How to initialize record from session variable in rails so that we need not to execute query for initializing a record?

Is there any way to initialize a record from session. for e.g I have a organization object and I put this in session object like
session[:organization] = organization
Now I made a custom method current_organization (I know about devise) like
def current_organization
Organization.new(session[:organization])
end
This will return organization object. My organization belongs_to a team a devise model and team has_many :organizations but when I call
current_team.organizations.includes?(current_organization)
in view. It is returning false even if it is included in team's organizations but doing this
current_team.organizations.reload.includes?(current_organization)
is returning true. I set the session variable with organization object before calling view where i am using above method. Is there any thing which I missed like I am not able to figure out the reason for not returning true even it is included?
Try saving the record first.
Until you save it into the database, it is likely not to show up when you query for the team's organization children.
session[:organization_id] = organization.id
def current_organization
Organization.find session[:organization_id]
end
Ok after some googling i found that instead of using
Organization.new(session[:organization])
I should use
Organization.instantiate(session[:organization])
From apidock I found that
instantiate(attributes, column_types = {}) public
Given an attributes hash, instantiate returns a new instance of the
appropriate class. Accepts only keys as strings.
For example, Post.all may return Comments, Messages, and Emails by
storing the record’s subclass in a type attribute. By calling
instantiate instead of new, finder methods ensure they get new
instances of the appropriate class for each record.

Unique values of a parent in has_many relationship

I have a model projectuser which has_many activities, and activities belongs_to projectuser. Now I have a collection of activities as #activities in a controller and I want to get the unique projectusers. How can I do this?
If #activities is a simple ruby collection (e.g. Array), then use this:
Projectuser.where(id: #activities.map(&:projectuser_id).uniq)
However, if your #activities object is an ActiveRelation (the result of an association call or query api call), you can do a more efficient lookup like this:
Projectuser.joins(:activities).merge(#activities)
The reason it is more efficient is because it avoids building a literal list of ids, which can get significantly harder on a db engine at it gets larger.

Trouble accessing nested model's attributes in home controller

I have a Model Form which has an has_many relationship to a model User. User belongs_to Form.
I'm trying to access the values in User from my HomeController:
#forms = Form.all
#forms_by_val = #forms.users.group_by(&:value)
But this is giving me the error. Any ideas how to fix?:
undefined method `users' for # Array:0x007fdb32672dd8>
#forms that is Form.all refer to the array that have Form instances. users method is only available to a Form instance. Not to an array of Form instances.
I think you are trying to do something like this.
#forms_by_val = #forms.map {|form| form.users }.flatten
This will give you an array of users that belong to individual forms.
If you want a unique list of users...
#forms_by_val = #forms.map {|form| form.users }.flatten.uniq

Resources