Rails using a variable find condition - ruby-on-rails

I am using Braintree for managing subscriptions in my Rails app.
I have a Subscription model that stores the braintree customer ID and subscription ID.
I want to filter active subscriptions in my Subscription model. So far I have
def find_active_subscriptions
#active_subscriptions = Braintree::Subscription.search do |search|
search.status.is "Active"
end
But now I want to use the subscription IDs in #active_subscriptions to find all of the objects in my local Subscription model with the same subscription IDs and put that into a variable such as #local_active_subscriptions.
The reason I have to do this is to use the local info to access Braintree::Address and only pull active addresses.
Thanks for the help.

One you have the #active_subscriptions you can collect all of the ids into an array and pass them right into the find method of your local Subscription model. I don't know what attributes you are using here, so I'm just making some guesses:
#active_subscription_ids = #active_subscriptions.collect(&:subscription_id)
#local_active_subscriptions = LocalSubscriptionModel.find(#active_subscription_ids)

I'm not sure what Braintree::Subscription.search returns, but if it's something akin to ActiveRecords, could you use something like:
#local_active_subscriptions = Subscription.where("id IN(?)", #active_subscriptions.map{ |act_subs| act_subs.id })
The .map function should put all the IDs into an array, and then ActiveRecord query would look for all the Subscriptions in your subscriptions table whose ID is in that array.
I'm not certain about mapping on Braintree::Subscriptions; I've never used that.
Edit
Like ctcherry said, you can also do the search with find. And I guess collect is good for mapping the ids into an array too. You could also maybe use #active_subscriptions.map(&:id)

Related

How to add attribute/property to each record/object in an array? Rails

I'm not sure if this is just a lacking of the Rails language, or if I am searching all the wrong things here on Stack Overflow, but I cannot find out how to add an attribute to each record in an array.
Here is an example of what I'm trying to do:
#news_stories.each do |individual_news_story|
#user_for_record = User.where(:id => individual_news_story[:user_id]).pluck('name', 'profile_image_url');
individual_news_story.attributes(:author_name) = #user_for_record[0][0]
individual_news_story.attributes(:author_avatar) = #user_for_record[0][1]
end
Any ideas?
If the NewsStory model (or whatever its name is) has a belongs_to relationship to User, then you don't have to do any of this. You can access the attributes of the associated User directly:
#news_stories.each do |news_story|
news_story.user.name # gives you the name of the associated user
news_story.user.profile_image_url # same for the avatar
end
To avoid an N+1 query, you can preload the associated user record for every news story at once by using includes in the NewsStory query:
NewsStory.includes(:user)... # rest of the query
If you do this, you won't need the #user_for_record query — Rails will do the heavy lifting for you, and you could even see a performance improvement, thanks to not issuing a separate pluck query for every single news story in the collection.
If you need to have those extra attributes there regardless:
You can select them as extra attributes in your NewsStory query:
NewsStory.
includes(:user).
joins(:user).
select([
NewsStory.arel_table[Arel.star],
User.arel_table[:name].as("author_name"),
User.arel_table[:profile_image_url].as("author_avatar"),
]).
where(...) # rest of the query
It looks like you're trying to cache the name and avatar of the user on the NewsStory model, in which case, what you want is this:
#news_stories.each do |individual_news_story|
user_for_record = User.find(individual_news_story.user_id)
individual_news_story.author_name = user_for_record.name
individual_news_story.author_avatar = user_for_record.profile_image_url
end
A couple of notes.
I've used find instead of where. find returns a single record identified by it's primary key (id); where returns an array of records. There are definitely more efficient ways to do this -- eager-loading, for one -- but since you're just starting out, I think it's more important to learn the basics before you dig into the advanced stuff to make things more performant.
I've gotten rid of the pluck call, because here again, you're just learning and pluck is a performance optimization useful when you're working with large amounts of data, and if that's what you're doing then activerecord has a batch api you should look into.
I've changed #user_for_record to user_for_record. The # denote instance variables in ruby. Instance variables are shared and accessible from any instance method in an instance of a class. In this case, all you need is a local variable.

How to get only one db record from couple of same?

I have records in the db table that can differ only by ids and creation/update time. How can I get only the unique records?
I tried this way, but it didn't work:
msg_to_user = user.messages.new_messages.uniq
I'll explain. User can follow post manually but also same post can be followed by user automatically. So I want to send only one message if post have been commented by someone.
1747 test message TamadaTours 12 new 2016-01-29 06:14:04.736869 2016-01-29 06:48:55.948529 32964382
1748 test message TamadaTours 12 new 2016-01-29 06:14:04.741184 2016-01-29 06:48:55.951371 32964382
All records in the database are uniq (at least because of ID column, which by default has a uniq constraint).
You would want to use DISTINCT:
Model.select('DISTINCT column_name1, column_name2')
Your question is flawed...
The point of having an id... otherwise known as primary_key... in a relational database is so that you can actively identify the unique records you want:
A primary key uniquely specifies a tuple within a table. In order for an attribute to be a good primary key it must not repeat
When you write... "How can I get only the unique records" ... the answer is to pull only the records based on their id.
If you refine your question to what you really want...
I want to send only one message if post have been commented by someone
--
In other words, you want to pull a collection of unique user_ids (no duplicates), to which you can send new messages?
To do this, you can use...
#recipients = Message.select(:user_id).distinct #-> all unique user_ids
If you're trying to pull the "new" messages for a user, but only show the first (if they're the same), you'll want to use something like the following:
#msg_to_user = user.messages.new_messages.uniq(:title)
Ref
A better pattern to implement would be to validate the uniqueness of new messages:
#app/models/message.rb
class Message < ActiveRecord::Base
validates :user_id, uniqueness: { scope: :message_id } #-> replace message_id with other unique identifier
end
This would ensure only one new message is present for a user.
you can also use group by in your query like this
Model.all.group("column_name")
One way to extract the data but get rid of the ORM context.
# maps every record to hash, remove the ID entry and then removes duplicates
msg_to_user = user.messages.new_messages.attributes.map { |e| e.except('ID') }.uniq

How to perform #find on an object without Active Model

Here's what's happend: I have gone and pulled a large amount of data from an API. This is nice, but it includes a lot of results.
When I do a result.find(id: api_id) I get all the results like find was never performed. #where does not work either. I'm assuming this is because its not extending from Active Model.
Key Question: How do I find, say, the name of a particular object in an active resource collection?
Object.find(id: api_id) in active resource is essentially doing an api request as in (uri_of_api)/objects/:api_id)
But the :find method on an array is a different aninmal. You can look up the array 'find' method here... http://www.ruby-doc.org/core-2.1.1/Enumerable.html#method-i-find
The correct format would be...
result.find{|rec| rec.id == api_id}

How to efficiently retrieve all record in rails 3.2 and assign them to a query-able object?

In our rails 3.2 app, we need to retrieve all customer records out of customer table and assign them to a variable customers and do query (such as .where(:active => true) on variable customers late on. There are 2 questions here:
what's the better way to retrieve all records?
Customer.all works. However according to rails document, it may have performance issue when Customer table gets large. We tried Customer.find_each and it has error "no block given (yield)".
How to make the variable customers query_able?
When performing query on variable customers (like customers.where(:active => true)), there is an error: undefined methodwhere' for #. It seems that thecustomersis an array object and can't takewhere. How can we retrievecustomers` in such a way it can be query-able?
Thanks for help.
In Rails < 4 .all makes database call immediately, loads records and returns array. Instead use "lazy" scoped method which returns chainable ActiveRecord::Relation object. E.g.:
customers = Customer.scoped
...
customers = customers.where(:active => true)
customers = customers.where(...)
etc...
And at the moment when you will need to load records and iterate over them you can call find_each:
customers.find_each do |customer|
...
end

Rails: Get relationship on array of objects

I don't know if there's a good answer for this. Let's say I have:
users = User.where(:location => "Utopia") #=> Returns [user1,user2,user3,user4]
I would like do something like:
users.photos #=> Returns all photos this group of users has
And simply get all the photos back without iterating over them. I ask because each iteration is a DB call. Is there any good way that does a single DB call?
The most straightforward way to do this is to use the eager loader:
users = User.where(:location => 'Utopia').includes(:photos)
That will fetch the users in one pass, then the relationships and their associated photos in another. You can wrap it all up into one call if you either use a JOIN or a subselect, it's your call, but it'll look something like this:
photos = Photo.includes(:user).where('users.location' => 'Utopia')
There's more information available in the Active Record Query Interface documentation in section 12.

Resources