Ask A Question

Notifications

You’re not receiving notifications from this thread.

Slow API Call any help?

Stephen Sizer asked in Rails

I call the api for some lifestyle nutrition objects using the bellow and it returns 700 objects. Its currently taking 25-30secs. The lifestyle items do not have any attachments so don't understand why the call takes so long.

removing the attachments from the jbuilder file returns the API call in 8-12 secs. Am I missing something?

I have the following models:

# == Schema Information
#
# Table name: lifestyle_nutritions
#
#  id                :bigint           not null, primary key
#  due_date          :datetime
#  last_activity     :datetime
#  created_at        :datetime         not null
#  updated_at        :datetime         not null
#  client_id         :bigint           not null
#  lifestyle_plan_id :bigint
#
# Indexes
#
#  index_lifestyle_nutritions_on_client_id          (client_id)
#  index_lifestyle_nutritions_on_lifestyle_plan_id  (lifestyle_plan_id)
#
# Foreign Keys
#
#  fk_rails_...  (client_id => clients.id)
#  fk_rails_...  (lifestyle_plan_id => lifestyle_plans.id)
#
class LifestyleNutrition < ApplicationRecord
  belongs_to :client
  belongs_to :lifestyle_plan, optional: true
  has_many :lifestyle_nutrition_items, dependent: :destroy
  accepts_nested_attributes_for :lifestyle_nutrition_items, allow_destroy: true
  has_many :lifestyle_comments, dependent: :destroy

  scope :lifestyle_nutrition_between, ->(range) { where(due_date: range )}
  scope :not_overdue_lifestyle_nutrition, ->(timezone) { where('due_date >= ?', timezone ? Time.now.in_time_zone(timezone).to_date : Date.today) }
  scope :future_lifestyle_nutrition, ->(timezone) { not_overdue_lifestyle_nutrition(timezone) }
  scope :future_lifestyle_nutrition_between, ->(range, timezone) { lifestyle_nutrition_between(range).future_lifestyle_nutrition(timezone) }
  scope :overdue_lifestyle_nutrition, ->(timezone) { where('due_date < ?', timezone ? Time.now.in_time_zone(timezone).to_date : Date.today) }
  scope :past_lifestyle_nutrition, ->(timezone) { overdue_lifestyle_nutrition(timezone) }
  scope :past_lifestyle_nutrition_between, ->(range, timezone) { lifestyle_nutrition_between(range).past_lifestyle_nutrition(timezone) } 
  scope :nutritions_between, ->(range) { where(due_date: range )}

  def complete?
    lifestyle_nutrition_items.count === lifestyle_nutrition_items.actioned.count
  end

  def state
    if client
      timezone = client.user.timezone
      status = complete? ? "complete" : "pending"
      if due_date
        if status === "complete"
          "complete"
        elsif status === "pending" && due_date < (timezone ? Time.now.in_time_zone(timezone).to_date : Date.today)
          "missed"
        else
          "pending"
        end
      else
        "pending"
      end
    end
  end
end
# == Schema Information
#
# Table name: lifestyle_nutrition_items
#
#  id                        :bigint           not null, primary key
#  completed                 :boolean
#  notes                     :text
#  notification_sent         :boolean          default(FALSE)
#  notification_time         :datetime
#  notification_time_string  :string
#  prescription_description  :text
#  created_at                :datetime         not null
#  updated_at                :datetime         not null
#  lifestyle_nutrition_id    :bigint           not null
#  lifestyle_prescription_id :bigint           not null
#  lifestyle_type_id         :bigint           not null
#
# Indexes
#
#  index_lifestyle_nutrition_items_on_lifestyle_nutrition_id     (lifestyle_nutrition_id)
#  index_lifestyle_nutrition_items_on_lifestyle_prescription_id  (lifestyle_prescription_id)
#  index_lifestyle_nutrition_items_on_lifestyle_type_id          (lifestyle_type_id)
#
# Foreign Keys
#
#  fk_rails_...  (lifestyle_nutrition_id => lifestyle_nutritions.id)
#  fk_rails_...  (lifestyle_prescription_id => lifestyle_prescriptions.id)
#  fk_rails_...  (lifestyle_type_id => lifestyle_types.id)
#
class LifestyleNutritionItem < ApplicationRecord
  belongs_to :lifestyle_nutrition
  belongs_to :lifestyle_type
  belongs_to :lifestyle_prescription
  has_many :attachments, as: :attachable, dependent: :destroy

  scope :completed, -> { where(completed: true) }
  scope :actioned, -> { where.not(completed: nil) }

  before_destroy :destroy_notifications 
  before_save :set_notification_time


  def destroy_notifications
    self.lifestyle_nutrition.client.coach.notifications.where(type: "LifestyleNotification").each do |n|
      if (n.params[:lifestyle_nutrition_item][:id] == self.id) 
        n.destroy
      end
    end
  end

  def set_notification_time
    if notification_time_string.present?
      date = lifestyle_nutrition.due_date
      self.notification_time = get_notification_time(date, notification_time_string)
    end
  end

  def get_notification_time(date, time)
    notification_send_time = date
    hours = time.split(":")[0].to_i
    mins = time.split(":")[1].to_i
    notification_send_time = notification_send_time.advance(hours: hours)
    if mins > 0
      notification_send_time = notification_send_time.advance(minutes: mins)
    end

    if lifestyle_nutrition.client.user.timezone.present?
      notification_send_time = notification_send_time.in_time_zone(lifestyle_nutrition.client.user.timezone)
    else 
      notification_send_time = notification_send_time.in_time_zone("London")
    end
    notification_send_time -= notification_send_time.utc_offset
    notification_send_time = notification_send_time.utc
  end
end
# == Schema Information
#
# Table name: attachments
#
#  id              :bigint           not null, primary key
#  attachable_type :string
#  attachment_url  :string
#  cleaned_up      :boolean          default(FALSE)
#  converted       :boolean          default(FALSE)
#  copied          :boolean          default(FALSE)
#  file_type       :string
#  name            :string
#  original_url    :string
#  size            :integer
#  created_at      :datetime         not null
#  updated_at      :datetime         not null
#  attachable_id   :integer
#
class Attachment < ApplicationRecord
    before_create :set_original_url
    after_create :uploadcare
    belongs_to :attachable, polymorphic: true

    def isVideo?
      vid = file_type.split("/")[0]
      vid === "video"
    end

    def mp4?
      mp4 = file_type.split("/")[1]
      mp4 === "mp4"
    end

    def needsConverting?
      isVideo?
    end

    private 

    def set_original_url
      self.original_url = attachment_url
    end

    def uploadcare
      UploadcareJob.set(wait: 1.minute).perform_later(id)
    end
end

Jbuilder file.

json.lifestyle_nutritions @lifestyle_nutritions.each do |lifestyle|
    json.id lifestyle.id 
    json.due_date lifestyle.due_date.strftime('%Y/%m/%d')
    json.lifestyle_plan_id lifestyle.lifestyle_plan_id
    json.lifestyle_nutrition_items_attributes lifestyle.lifestyle_nutrition_items.order(:created_at).each do |item|
        json.id item.id
        json.lifestyle_type item.lifestyle_type.name 
        json.lifestyle_type_id item.lifestyle_type_id 
        json.lifestyle_prescription item.lifestyle_prescription.name 
        json.lifestyle_prescription_id item.lifestyle_prescription_id
        json.notification_time item.notification_time
        json.notification_time_string item.notification_time_string
        json.prescription_description item.prescription_description
        json.notes item.notes
        json.completed item.completed

        json.attachments item.attachments do |attachment|
            json.id attachment.id
            json.attachment_url attachment.attachment_url
            json.file_type attachment.file_type
        end
    end
    json.comments lifestyle.lifestyle_comments.order(:created_at).each do |comment|
        json.id comment.id
        json.lifestyle_nutrition_id comment.lifestyle_nutrition_id
        json.body comment.body 
        json.created_at comment.created_at
        json.commentable_type comment.commentable_type
        json.commenter_name comment.commentable_type == "Client" ? comment.commentable.name : comment.commentable.user.name
        json.commenter_initials comment.commentable && comment.commentable.name ? comment.commentable.name.initials : ""
        json.avatar_url comment.commentable && comment.commentable.user.avatar ? comment.commentable.user.avatar.url : nil
        json.attachments comment.attachments do |attachment|
            json.id attachment.id
            json.attachment_url attachment.attachment_url
            json.file_type attachment.file_type
        end
    end
end
Reply
Join the discussion
Create an account Log in

Want to stay up-to-date with Ruby on Rails?

Join 82,329+ developers who get early access to new tutorials, screencasts, articles, and more.

    We care about the protection of your data. Read our Privacy Policy.