Я пытаюсь реорганизовать код в моем API-интерфейсе rails, который отправляет аналитические данные для диаграмм ( в настоящее время работает ). Поскольку у меня такой же код выполняется для 1. Закладки, 2. Журналы, 3. Цели, и это не очень сухо.

Я пытаюсь создать 1 запрос к базе данных (используя PostgreSQL), который может получать тип (закладка, цель, журнал) в качестве параметра ... Я пробовал использовать [: type] и жестко кодировать «тип», где закладка использовалась для пример...

Существующий (рабочий) код, который я хочу реорганизовать:

class AnalyticsController < ApplicationController
  before_action :authenticate_user

  def entries_by_date
    bookmarks = current_user.bookmarks.group_by_day(
      :created_at,
      format: '%Y-%m-%d',
      range: 4.weeks.ago.midnight..Time.zone.now
    ).count
    journals = current_user.journals.group_by_day(
      :created_at,
      format: '%Y-%m-%d',
      range: 4.weeks.ago.midnight..Time.zone.now
    ).count
    goals = current_user.goals.group_by_day(
      :created_at,
      format: '%Y-%m-%d',
      range: 4.weeks.ago.midnight..Time.zone.now
    ).count

    entries_array = []
    entries_array.push(@bookmarks)
    entries_array.push(goals)
    entries_array.push(journals)

    total_entries_by_date = entries_array.inject { |memo, el| memo.merge(el) { |_k, old_v, new_v| old_v + new_v } }

    render json: {
      total_entries_by_date: total_entries_by_date,
      bookmarks: bookmarks,
      goals: goals,
      journals: journals
    }
  end
end

Я пробовал это:

.... 

  def entries_by_date
    def fetch_activity(type)
      current_user[:type].group_by_day(
        :created_at,
        format: '%Y-%m-%d',
        range: 4.weeks.ago.midnight..Time.zone.now
      ).count
    end

    @bookmarks = fetch_activity(bookmarks)
    @goals = fetch_activity(goals)
    @journals = fetch_activity(journals) 


... (cont'd)

Я пробовал current_user.type ... >> undefined локальную переменную или закладки метода

Я пробовал current_user. [: Type] ... >> "Синтаксическая ошибка, неизвестно ["

Я пробовал current_user [: type] ... >> NameError (неопределенная локальная переменная или метод `закладки '

Я пробовал current_user.% {Type} ... & current_user. # {Type} ... & current_user. $ {Type}

Любые рекомендации будут очень признательны :) Я новичок в мире Ruby on Rails и с нетерпением жду, когда мой код станет немного суше, когда я лучше пойму, как повторно использовать переменные, передаваемые в запрос к базе данных

1
Emma 21 Авг 2020 в 10:01

2 ответа

Лучший ответ

Вы были довольно близки к решению. Просто используйте public_send и передать имя метода, который вы хотите вызвать, в виде строки или символа.

def entries_by_date
  @bookmarks = fetch_activity(:bookmarks)
  @goals = fetch_activity(:goals)
  @journals = fetch_activity(:journals) 

  # ...
end

private

def fetch_activity(type)
  current_user.public_send(type).group_by_day(
    :created_at,
    format: '%Y-%m-%d',
    range: 4.weeks.ago.midnight..Time.zone.now
  ).count
end

@bookmarks = fetch_activity(bookmarks)
@goals = fetch_activity(goals)
@journals = fetch_activity(journals) 
3
spickermann 21 Авг 2020 в 07:16

Чтобы немного улучшить ответ Спикермана - вам следует рассмотреть возможность извлечения бизнес-логики из контроллера и поместить ее в модель, к которой она принадлежит:

class User < ApplicationRecord
  # Gets a single activity 
  def fetch_activity(type)
    public_send(type).group_by_day(
      :created_at,
      format: '%Y-%m-%d',
      range: 4.weeks.ago.midnight..Time.zone.now
    ).count
  end

  # Gets a hash containing the counts of the users activities and total 
  def fetch_activities(*types)
    types.each_with_object({}) do |key, hash|
      hash[key] = fetch_activity(key)
    end.then do |hash|
      hash.merge(total_entries_by_date: hash.values.sum)
    end
  end
  # ... 
end

Модели намного проще тестировать, чем контроллеры, поскольку вы можете просто настроить его и вызвать метод прямо на объекте, вместо того, чтобы идти через HTTP и анализировать ответ - это ключевая причина, по которой ваши контроллеры должны быть как можно более тонкими:

class AnalyticsController < ApplicationController
  before_action :authenticate_user

  def entries_by_date
    render json: current_user.fetch_activities(:bookmarks, :goals, :journals)
  end
end
4
max 21 Авг 2020 в 07:46