Overriding collection<< method - ruby-on-rails

I have two models Board and Feed in many-to-many relationship with join :through model Subscription.
Lately I added root_id field to Subscription, and I'd like to setup this field when I do #board.feeds << #feed So it would be like #board.feeds << #feed, root_id: 10
According to rails docs I can override these methods, but not sure how.
def feeds << (??? - how should I setup arguments here? )
super
#super creates new Subscription rekord, but how can I access it
#to set root_id field?
#For now let say I accessed it as subscription
if root_id
subscription.root_id = root_id
else
subscription.root_id = self.id
end
subscription.save
#return something regular collection << returns
end

Does the root_id on Subscription represent any aspect of the Board or Feed? You could maybe do that work in a callback on Subscription instead:
# Subscription
before_save :assign_root_id
def assign_root_id
self.root_id = feed.user.id # Whatever root is ....
end

Related

How to get multiple values of a record with map

In my application I can have multiple accounts and accounts can have multiple emails. I have a method that counts all the unique email from every account, but that is not what I want however.
Instead I want to return all the unique email from just one account NOT all, as the method is currently doing.
Here is my current method:
class AccountEmails
def self.count
accounts = Account.all
alert = accounts.map do |a|
a.users.first.alert_email.split(",")
end
billing = accounts.map do |a|
a.users.first.billing_email.split(",")
end
user = accounts.map do |a|
a.users.first.email.split(",")
end
snitch = accounts.map do |a|
a.snitches.map { |s| s.alert_email.split(",") }
end
[alert, billing, user, snitch].flatten.uniq.count
end
end
This will return all the email that are unique from all the accounts. I want to return all the unique email for each account, so account 1 could have four unique email and account 2 could have five unique email.
It sounds like you're saying you want a single method that gives you all the unique emails for each account. If I'm understanding you, I would do something like this:
class Account
def all_emails
# I'm assuming here that you actually only want the unique
# emails on the first user for each account
user = self.users.first
[
user.alert_email.split(","),
user.billing_email.split(","),
user.email.split(","),
self.snitches.map{|snitch| snitch.alert_email.split(",") }
].flatten
end
def unique_emails
all_emails.uniq
end
end
class AccountEmails
def self.unique
Account.all.includes(:snitches).map do |account|
account.uniq_emails
end
end
def self.count
uniq.flatten.count
end
end

Rails 4 Create Related Object After Save

I have two models with the [fields]:
Order [:date]
Delivery Slot [:day]
Order belongs_to :delivery_slot
When an order is created, I want a delivery slot to be created with the :day set to the order :date.
So far I have created a new method create_delivery_slots in the Order controller that creates a Delivery Slot when the Order is created, but where I am stumped is, how do I get the Order :date in the Delivery Slot :day field?
#Create delivery slots if they dont already exist
def create_delivery_slots
existingslots = []
existingslots = DeliverySlot.all.select {|slot| slot.day == #order.date}
if existingslots.empty?
slot = DeliverySlot.new(:day => #order.date)
slot.save!
end
I have tried multiple approaches, but no luck. My gut tells me its something to do with strong parameters but I can't figure it out...
I'm not sure exactly of how you're set up but you'll probably want something like this:
class Order < ActiveRecord::Base
has_a :delivery_slot
after_create => :create_delivery_slots
.
#other code stuffs
.
.
private
def create_delivery_slots
existingslots = []
existingslots = DeliverySlot.all.select {|slot| slot.day == self.date}
if existingslots.empty?
slot = DeliverySlot.new(:day => self.date)
slot.save!
end
end
end
That's untested but it should be basically what you need.

Rails 3, adding joins to default_scope for association of current_user

In my app i have a schema of Users and Tickets, each User can be subscribed to many Tickets and viceversa.
For each ticket i fetch from the database, i want to display if current_user is subscribed or not to the ticket itself.
An example of my query is as follows:
#tickets = current_user.tickets.limit(10).order('created_at DESC')
Can i do it using a default_scope with a join in Ticket model?, i need it to return an additional field with a simple true or false, or nil.
Thank you.
Example 1 - To figure out whether an individual ticket is subscribed:
ticket = Ticket.find(id)
#ticket_is_subscribed = current_user.tickets.any? { |t| t == ticket }
Example 2 - If you want simply an array with all ticket IDs subscribed by the current user:
subscribed_ids = current_user.tickets.pluck(:id)
#ticket_is_subscribed = subscribed_ids.include?(ticket.id)
Example 3 - You could generate an array of arrays that gives you true or false for each ticket.id.
subscribed_ids = current_user.tickets.pluck(:id)
#all_subscribed_tickets = Ticket.all.pluck(:id).map { |id| [id, subscribed_ids.include?(id)] }
The question is a bit vague so I imagine the case is you fetch a bunch of tickets and show if current user have it. If having, show "yes", else show "now".
You can have a model method in Ticket to judge it.
class Ticket < ActiveRecord::Base
def is_buyer?(buyer)
user == buyer ? "yes" : "no"
end
end
# In controller
#tickets = Ticket.page(1)
# In view
- #tickets.each do |ticket|
= ticket.name
= ticket.is_buyer?(current_user)

Rails model optimization

I have a List model below, it has a has_and_belongs_to_many association with recipients. The purpose of the method make_recipient_lists is to save a parsed csv of numbers(initial parameter) in this format [[num1],[num2],[num3]...].
add_recipients work by finding existing recipients then adding them to the list or creating new recipients.
This whole process works well for small amount, 20k of numbers in 28minutes. However, the greater the number, the longer it takes exponentially, 70k took 14hours. Probably because it was checking for duplicates to a cached current_lists.
Question is, is there any way to make this faster? I am probably approaching this problem wrong. Thanks!
class List < ActiveRecord::Base
#other methods above
def make_recipient_lists(numbers,options)
rejected_numbers = []
account = self.user.account
#caching recipients
current_recipients = self.recipients
numbers.each do |num|
add_recipient(num[0], current_recipients)
end
end
def add_recipient(num, current_recipients)
account = self.user.account
recipient = current_recipients.where(number:num, account_id: account.id).first
recipient ||= current_recipients.create!(number:num, account_id: account.id)
recipient
end
end
You could do something like this. I have not tested this, but you get the idea.
def make_recipient_lists(numbers, options)
rejected_numbers = []
account = self.user.account
existing_numbers = self.recipients.where(number: numbers, account_id: account.id).map(&:number)
new_records = (numbers - existing_numbers).map {|n| {number: n, account_id: account.id, list_id: self.id} }
Recipient.create new_records
end
I think, you should use rails active_record query interface. you can use method find_or_create method for this: It will make your queries faster. change your method like this, and check the time difference:
def make_recipient_lists(numbers,options)
rejected_numbers = []
account = self.user.account
#caching recipients
current_recipients = self.recipients
numbers.each do |num|
self.recipients.find_or_create_by(number: num, account_id: account.id)
end
end
Hope it will help. Thanks.

find_each Active Record Querying

I have this method in my model to allow my view to display all equipment associated with a vehicle. Should I be using find_each to check batches of records, and if so, how would I break this method down to use it?
def equip(vehicle)
equip = Vehicle.find_by_id(vehicle).equipments.
where("vehicle_id = ?", vehicle).all
end
Don't use .all at the end, it will trigger the query when its called and will be a pain as perfomances.
Also, you should use this syntax (Rails 3):
def equip(vehicle)
equip = Equipment.where(vehicle_id: vehicle.try(:id) || vehicle)
end
Using this, you only use the Equipment model, which will just use the equipments SQL table (not 2 or more).
# This line
vehicle.try(:id) || vehicle
# Allows you to pass both a Vehicle object or a vehicle id to your method
Also, if you have already an instance of vehicle, you could use:
def equip(vehicle)
equip = Vehicle.where(id: vehicle).first.equipments
# or with your syntax:
equip = Vehicle.find(vehicle).equipments
end

Resources