Поиск способов не проверять БД регулярно в рельсах - PullRequest
1 голос
/ 31 октября 2009

У меня есть приложение, в котором приложению необходимо проверять, ожидает ли один пользователь другого пользователя при загрузке страницы. У меня есть записи, которые выглядят так:

def self.up
    create_table :calls do |t|
      t.string   "user1_id"
      t.string   "user2_id"
      t.boolean  "active", :default=>false
      t.string   "meeting_url"
      t.string "embed_url"
      t.timestamps
    end

В настоящее время приложение проверяет таблицу вызовов на наличие любых вызовов, которые совпадают с идентификаторами пользователя, и если они активны == true. Если есть результаты, они отображаются для пользователя. Проблема в том, что это требует вызова базы данных для каждой загрузки страницы. Поэтому мои вопросы таковы:

1) Это самый эффективный способ сделать это? (Я явно скептически отношусь) 2) Если да, то как лучше всего это сделать СУЩЕСТВЕННЫМ способом?

Большое спасибо

Dave

Ответы [ 2 ]

0 голосов
/ 31 октября 2009

Если вашему приложению нужно знать, есть ли у пользователя какие-либо вызовы, ожидающие при каждой загрузке страницы, и эта информация хранится только в базе данных, тогда да, я бы ожидал, что вам придется запросить в базе данных эту информацию при каждой загрузке страницы.

Что касается DRYness, Rails предоставляет множество механизмов по всему стеку MVC, которые гарантируют, что все будет СУХОЙ и поддерживаемой:

В модели вы можете добавить метод класса в модель Call, чтобы инкапсулировать логику для запросов ожидающих вызовов. Это может быть что-то вроде:

class Call < ActiveRecord::Base

def self.awaiting_for_user user
    self.all(:conditions => ['user_id = ? AND active = true', user])
end

Инкапсулируя запрос в таком методе, вы гарантируете, что если базовая логика для запроса этой информации изменится, ваши вызовы этого метода не будут.

Вместо добавления этого вызова метода к каждому действию контроллера (index, show и т. Д.), Вы можете использовать методы контроллера before_filter / around_filter / after_filters для запуска этого кода на наборах контроллеров / действий.

class ApplicationController
    before_filter :load_current_user
    before_filter :load_current_users_calls

....
protected

    def load_current_user
        # You could encapsulate this method in your User model
        @user = User.find(session[:user_id])
    end

    def load_current_users_calls
         @calls = Call.awaiting_for_user(@user)
    end

Используйте параметры before_filter, такие как: кроме и: только, чтобы точно определить использование фильтра в определенных действиях контроллера. Кроме того, объявляя фактические методы load_current_users_calls в ApplicationController, гарантирует, что каждый субклассированный контроллер имеет этот метод, вам не нужно помещать объявление before_filter в ApplicationController - вы можете просто поместить его в любой контроллер, который вы хотите запустить before_filter.

А в слое вида вы можете сделать частичное, чтобы легко отображать @calls в вашем стандартном макете. Вы можете добавить что-то вроде этого в свой макет:

<%- if @calls && !@calls.blank? -%>
<%= render :partial => 'awaiting_calls_display', :locals => {:calls => @class} =%>
<%- end -%>

Или, если это не вписывается в ваш макет, вы можете вызвать его из любого подходящего представления.

0 голосов
/ 31 октября 2009

Эта модель кажется мне немного запутанной. Именно то, что user1_id и user2_id , в частности, вызывает у меня хриплое чувство - это говорит мне, что вам все равно, кто кого ждет, что нет никакой разницы между двумя пользователями, и что вы счастливы, проверяя два столбца с «ИЛИ» каждый раз, когда вы хотите найти пользователя. Это беспорядок как для Rails, так и для SQL.

Это также не бизнес-проблема, которую вы описываете. Отношения между этими двумя пользователями не совершенно симметричны: один человек ждет другого. И вам ясно, что есть что, но вы не моделируете это. Или, если да, вы их плохо называете.

У меня нет точного смысла вашего заявления по этому поводу, но я бы, вероятно, сделал две вещи, чтобы очистить это:

  1. Уточните эти пользовательские поля в асимметричные отношения: возможно, инициатор и получатель. Вы можете назвать их caller_id и callee_id . Без разницы. Тогда каждый сеанс должен только проверять поле callee_id (я думаю), чтобы увидеть, ждет ли кто-то этого пользователя. Этого может быть достаточно. Если это так, не беспокойтесь о втором шаге.

  2. Перенесите эти отношения ожидания в отдельную, более простую модель, оптимизированную для быстрой записи и удаления. Когда кто-то пытается инициировать вызов с кем-то еще, вы записываете в это хранилище Ожидание, в котором указан получатель. Вероятно, я бы использовал memcached непосредственно для этого вместо базы данных - тогда у вас практически нет задержки, и частые чтения и обновления не будут тормозить другие операции. (Или, в зависимости от используемой вами технологии базы данных, это может быть одним из тех редких случаев, когда требуется таблица на основе памяти.)

Мне кажется, что вы сначала думаете о данных и пытаетесь привести свой код в соответствие с имеющейся у вас структурой таблицы. Это не оптимально для Rails. Сначала подумайте о своем поведении и заставьте ваши модели данных адаптироваться к тому, что вы хотите, чтобы пользователи могли делать.

...