All threads / Slow API Call any help?

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
Join the discussion

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

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

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

    logo Created with Sketch.

    Ruby on Rails tutorials, guides, and screencasts for web developers learning Ruby, Rails, Javascript, Turbolinks, Stimulus.js, Vue.js, and more. Icons by Icons8

    © 2021 GoRails, LLC. All rights reserved.