Sum ActiveRecord Relationship (Model + Model = Array?) - ruby-on-rails

I'm trying to sum two Active Model Relationship and order it by created_at.
The sum of dogs and cats make an Array. So I try to sort this array by created_at with .sort_by( &:created_at ) but I get this strange error:
dogs = current_user.dogs
cats = current_user.cats
total = (dogs + cats).sort_by( &:created_at )
comparison of ActiveSupport::TimeWithZone with nil failed
There is another best way to sum two active record relationship and order it by created_at ?
Thank you very much.

One of your results has a created_at of nil it seems like, which is why you're getting that error. You can do the following to filter nil results
dogs = current_user.dogs.where.not(created_at: nil)
cats = current_user.cats.where.not(created_at: nil)
sorted_results = (dogs + cats).sort_by(&:created_at)
If you want to see which record(s) have created_at as nil do
nil_created_at_dogs = current_user.dogs.where(created_at: nil)
nil_created_at_cats = current_user.cats.where(created_at: nil)

I solve the problem.
If use .where, all works properly.
dogs = Dog.where(user_id: current_user.id)
cats = Cat.where(user_id: current_user.id)
total = (dogs + cats).sort_by( &:created_at )
I don't know why, but this is the way.

Related

Activerecord query where current employer is X and previous employer is Y

Basically I'd like to return all people whose current job title is X and whose previous job title is Y. As an example, I have a talent whose current emnployment is "Airbnb (company_id = 1)" and whose previous employment is at "Youtube (company_id = 2)".
If I run a query to find talent where current employment is Airbnb:
Talent.joins(:job_histories).where(["job_histories.company_id = ? and job_histories.end_year = ?", 1, "Present"])
I get the person.
If I run a query where previous employment is Youtube (hence the end_year != "Present" below)
Talent.joins(:job_histories).where(["job_histories.company_id = ? and job_histories.end_year != ?", 2, "Present"])
I also get the same person.
However, if I chain them together to find talents where current employer is Airbnb AND previous employer is Youtube, like this:
#talents = Talent.all
#talents = #talents.joins(:job_histories).where(["job_histories.company_id = ? and job_histories.end_year = ?", 1, "Present"])
#talents = #talents.joins(:job_histories).where(["job_histories.company_id = ? and job_histories.end_year != ?", 2, "Present"])
I do not get any results. I've tried several variations of the query but none return anything.
The only way I can get it to work is by using the first query and then looping over each talent to find where job_histories.company_id == 2.
if params[:advanced_current_company] && params[:advanced_previous_company]
#talents = #talents.joins(:job_histories).where(job_histories: { company_id: params[:advanced_current_company] }).distinct if params[:advanced_current_company]
#talents.each do |talent|
talent.job_histories.each do |job_history|
if job_history.company_id == params[:advanced_previous_company][0].to_i
new_talents.append(talent.id)
end
end
end
#talents = Talent.where(id: new_talents)
end
Any direction would be amazing. Thanks!
You had the right idea with a double join of the job_histories, but you need to alias the job_histories table names to be able to differentiate between them in the query, as otherwise activerecord will think it's only one join that needs to be done.
Talent.joins("INNER JOIN job_histories as jh1 ON jh1.talent_id = talents.id")
.joins("INNER JOIN job_histories as jh2 ON jh2.talent_id = talents.id")
.where("jh1.company_id = ? and jh1.end_year = ?", 1, "Present")
.where("jh2.company_id = ? and jh2.end_year != ?", 2, "Present")

Combine two ActiveRecord results and sort by a shared joined table attribute

I have a Convo table and a GroupMeeting table that both are associated with a Msg table.
I want to find all the instances where the current_user has convos or group_meetings with msgs, combine the two, and then show both together to the user in order of the last msg.created_at
Here I have defined both:
#convos = Convo.includes(:msgs).where("sender_id = ? OR recipient_id = ?", current_user, current_user).where.not(:msgs => { :id => nil }).merge(Msg.order(created_at: :desc))
#group_meetings = current_user.group_meetings.includes(:msgs).where.not(:msgs => { :id => nil }).merge(Msg.order(created_at: :desc))
And then combined them together:
#convos = #convos + #group_meetings
What I can't figure out is how to now sort them by msg.created_at
I have tried the following:
#convos = (#convos + #group_meetings).sort_by(&:"#{msg.created_at}")
#convos.order('msg.created_at DESC')
These all seem to be server-side sorting though. How can I sort these based off the join table, after the array has been created?
Please let me know if I need to supply any other details. Thank you!!
You can try the following:
(#convos + #group_meetings).sort_by { |item| item.msgs.minimum(:created_at) }

Rails 5: iteration with condition to map matching records

I have this method in my rating/rating.rb Model, where I basically need to create array of arrays with matching inventory and rating IDs:
def inventory_ratings
inventory = Inventory::Inventory.where(id: inv).order(date: :desc)
rating = Rating::Rating.where(id: rtg).order(valid_from: :desc)
columns = [:inventory_id, :rating_id]
values = inventory.map {|inv|
if (inv.position_id == rating.position_id &&
rating.valid_from..rating.valid_to.include?(inv.date))
r = rating.id
end
[ inv.id, r ]
}
Rating::InventoryRating.import columns, values, validate: false
end
At the moment I get this error:
NoMethodError: undefined method "position_id" for #<Rating::Rating::ActiveRecord_Relation:0x007ffff6067bf8> since I probably have to somehow iterate through each rating to get position_id, valid_from and valid_to.
How do I add that extra iteration so each inventory record iterates through each rating record and maps if it matches IF statement, please? Thank you!
How about this:
values = []
inventory.each do |inv|
values.concat([inv.id].product(rating.where('position_id = ? AND valid_from <= ? AND valid_to >= ?', inv.position_id, inv.date, inv.date).ids))
end.uniq.compact

Filterring ActiveRecord Relation...if there are no matches. (Null the active record relation)

I have a dashboard that allows for filtering of the results by different parameters. I build methods to filter the results by the given criteria. One area where I'm having trouble is if the previous line should null out the active record relation. Should I just put a bunch of if present? stat
def find_website_stats(options = {})
if options[:date_between].present?
start_date = options[:date_between].split(/-/).first.to_date
end_date = options[:date_between].split(/-/).last.to_date + 1
elsif options[:start_date].present?
start_date = options[:start_date].to_date
end_date = options[:end_date].to_date + 1 if options[:end_date].present?
end
contractor_name = options[:search_contractor] if options[:search_contractor].present?
distributor_name = options[:search_distributor] if options[:search_distributor].present?
distributor_ids = options[:with_distributor] if options[:with_distributor].present?
contractor_ids = options[:with_contractor] if options[:with_contractor].present?
with_country = options[:with_country] if options[:with_country].present?
with_state = options[:with_state] if options[:with_state].present?
search_city = options[:search_city] if options[:search_city].present?
web_stats = self.website_stats
if web_stats.present?
web_stats = web_stats.where(contractor_id: [*contractor_ids]) if contractor_ids.present?
if distributor_ids.present?
web_stat_ids = DistributorWebsiteStat.where(distributor_id: [*distributor_ids]).pluck(:website_stat_id)
web_stats = web_stats.where(id: [*web_stat_ids])
end
web_stats = web_stats.where(date_recorded: start_date..end_date) if start_date.present? && end_date.present?
web_stats = web_stats.with_country(with_country) if with_country.present?
web_stats = web_stats.with_state(with_state) if with_state.present?
web_stats = web_stats.search_city(search_city) if search_city.present?
#untested
if contractor_name.present?
searched_contractor_ids = Brand.search_contractor(contractor_name).pluck(:id)
web_stats = web_stats.where(contractor_id: [*searched_contractor_ids])
end
if distributor_name.present?
searched_distributor_ids = Brand.search_distributor(distributor_name).pluck(:id)
web_stat_ids = DistributorWebsiteStat.where(distributor_id: [*searched_distributor_ids])
web_stats = web_stats.where(id: [*web_stat_ids])
end
#end untested
end
web_stats
end
Where I'm specifically having a problem right now is the line that says if web_stat_ids.present?
So at first I grab all the website stats this object is associated with and then look to see if there are any for the given distributor.
If there is none for the given distributor web_stat_ids obviously returns nil
Then when I go to the line web_stats.where(id: [*web_stat_ids]) that's obviously going to return the same thing that I had before, rather than an empty active record relation, which is what I need it to be?
If I make this an empty array the next few statements with "where" won't work because it's an array and not an active record relation.
I know I can wrap this stuff in a bunch of if present? && statements...but I was wondering if there is a better solution to my problem?
In case anyone else is looking for this, found the answer from this SO post: How to return an empty ActiveRecord relation?
Model.none rails 4+

Sum and Group Query doesn't group

I need to filter records and then sum and group those records, in my controller I have done it like so:
def view
#templates = Template.where("user_id = #{current_user.id} OR user_id = 1").where("category = 5")
#user_docs = Doc.where("user_id = #{current_user.id}")
#transactions = Transaction.where("doc_id in (?)", #user_docs.map(&:id)).where("template_id in (?)", #templates.map(&:id))
#month = #transactions.select("DATE_TRUNC('month', date) AS month, SUM(amount) AS total_amount_per_month").group('month')
end
It gives an error with the month grouping and the amount is the total of all the months summed in my view, any idea why the above isn't working? What am I doing wrong?
The reason I got an error at the date was because the date was added later to my model with a migration and I didn't add it to attributes accessible. After that the error was fixed.

Resources