Лучший способ объединить фрагмент и объект, кэширующийся для memcached и направляющих

es7 way, (iterator, freeze), использование:

const ThreeWiseMen = new Enum('Melchior', 'Caspar', 'Balthazar')

for (let name of ThreeWiseMen)
    console.log(name)


// with a given key
let key = ThreeWiseMen.Melchior

console.log(key in ThreeWiseMen) // true (string conversion, also true: 'Melchior' in ThreeWiseMen)

for (let entry from key.enum)
     console.log(entry)


// prevent alteration (throws TypeError in strict mode)
ThreeWiseMen.Me = 'Me too!'
ThreeWiseMen.Melchior.name = 'Foo'

код:

class EnumKey {

    constructor(props) { Object.freeze(Object.assign(this, props)) }

    toString() { return this.name }

}

export class Enum {

    constructor(...keys) {

        for (let [index, key] of keys.entries()) {

            Object.defineProperty(this, key, {

                value: new EnumKey({ name:key, index, enum:this }),
                enumerable: true,

            })

        }

        Object.freeze(this)

    }

    *[Symbol.iterator]() {

        for (let key of Object.keys(this))
            yield this[key]

    }

    toString() { return [...this].join(', ') }

}
10
задан Jim Puls 23 June 2009 в 20:20
поделиться

4 ответа

Подключаемый модуль блокировки Эвана Уивера решает эту проблему.

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

# in FooController#show
@foo_finder = lambda{ Foo.find_slow_stuff }

# in foo/show.html.erb
cache 'foo_slow_stuff' do
  @foo_finder.call.each do 
    ...
  end
end

Если вы знакомы с основами метапрограммирования Ruby, достаточно легко обернуть это в более чистый API на ваш вкус.

Это лучше, чем размещение кода поиска непосредственно в представлении:

  • сохраняет код средства поиска там, где разработчики ожидают его по соглашению
  • , при этом представление игнорирует название модели / метод, позволяя более подробно просматривать reuse

Я думаю, что cache_fu может иметь аналогичную функциональность в одной из своих версий / форков, но не могу вспомнить конкретно.

Преимущество, которое вы получаете от memcached, напрямую связано с частотой попаданий в ваш кеш. Будьте осторожны, чтобы не тратить впустую емкость кэша и не вызывать ненужных промахов, кэшируя один и тот же контент несколько раз. Например, не кэшируйте одновременно набор объектов записи и их фрагмент HTML. Обычно кэширование фрагментов обеспечивает лучшую производительность, но на самом деле это зависит от специфики вашего приложения.

12
ответ дан 3 December 2019 в 20:43
поделиться

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

Я бы создал новый метод в модели:

  class Post
    def self.recent(count)
      find(:all, :limit=> count, :order=>"updated_at DESC")
    end
  end

затем использовал бы его в представлении:

<% cache("recent_posts", :expires_in => 30.minutes) do %>
  <% Post.recent(20).each do |post| %>
     ...
  <% end %>
<% end %>

Для ясности вы также можете рассмотреть возможность перемещения рендеринга недавний пост в отдельную часть:

<% cache("recent_posts", :expires_in => 30.minutes) do %>
  <%= render :partial => "recent_post", :collection => Post.recent(20) %>
<% end %>
3
ответ дан 3 December 2019 в 20:43
поделиться

Вы также можете изучить

Документы кэша фрагментов

, которые позволяют вам делать это:

<% cache("recent_posts", :expires_in => 30.minutes) do %>
  ...
<% end %>

Контроллер

unless fragment_exist?("recent_posts")
  @posts = Post.find(:all, :limit=>20, :order=>"updated_at DESC")
end

Хотя я признаю, что проблема DRY все еще возникает В заголовке нужно указать имя ключа в двух местах. Обычно я делаю это так же, как предлагал Ларс, но на самом деле это зависит от вкуса. Другие разработчики, которых я знаю, придерживаются проверки наличия фрагментов.

Обновление:

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

# File vendor/rails/actionpack/lib/action_controller/caching/fragments.rb, line 33
def fragment_cache_key(key)
  ActiveSupport::Cache.expand_cache_key(key.is_a?(Hash) ? url_for(key).split("://").last : key, :views)
end
1
ответ дан 3 December 2019 в 20:43
поделиться

Ларс действительно хорошо отмечает небольшую вероятность сбоя при использовании:

unless fragment_exist?("recent_posts")

, потому что между проверкой кеша и его использованием есть промежуток.

Плагин, о котором упоминает Джейсон (Interlock), очень изящно справляется с этим, предполагая, что если вы проверяете наличие фрагмента, то вы, вероятно, также будете использовать этот фрагмент и, таким образом, кэшируете содержимое локально. Я использую Interlock именно по этим причинам.

1
ответ дан 3 December 2019 в 20:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: