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(', ') }
}
Подключаемый модуль блокировки Эвана Уивера решает эту проблему.
Вы также можете легко реализовать что-то подобное самостоятельно, если вам нужно другое поведение, например, более детальный контроль. Основная идея состоит в том, чтобы обернуть код вашего контроллера в блок, который фактически выполняется только в том случае, если представлению нужны эти данные:
# 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 на ваш вкус.
Это лучше, чем размещение кода поиска непосредственно в представлении:
Я думаю, что cache_fu может иметь аналогичную функциональность в одной из своих версий / форков, но не могу вспомнить конкретно.
Преимущество, которое вы получаете от memcached, напрямую связано с частотой попаданий в ваш кеш. Будьте осторожны, чтобы не тратить впустую емкость кэша и не вызывать ненужных промахов, кэшируя один и тот же контент несколько раз. Например, не кэшируйте одновременно набор объектов записи и их фрагмент HTML. Обычно кэширование фрагментов обеспечивает лучшую производительность, но на самом деле это зависит от специфики вашего приложения.
Что произойдет, если срок действия кеша истечет между временем, когда вы проверите его в контроллере и время, когда оно проверяется в рендеринге представления?
Я бы создал новый метод в модели:
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 %>
Вы также можете изучить
, которые позволяют вам делать это:
<% 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
Ларс действительно хорошо отмечает небольшую вероятность сбоя при использовании:
unless fragment_exist?("recent_posts")
, потому что между проверкой кеша и его использованием есть промежуток.
Плагин, о котором упоминает Джейсон (Interlock), очень изящно справляется с этим, предполагая, что если вы проверяете наличие фрагмента, то вы, вероятно, также будете использовать этот фрагмент и, таким образом, кэшируете содержимое локально. Я использую Interlock именно по этим причинам.