我有一个Rails 3应用程序,正在实现一个配置文件完整性类型的功能。当用户登录应用程序时,应该向他/她展示制作"完整"配置文件的进度。因此,我在应用程序初始化时使用一个单例类填充需求。单例元素有一个数组,@requirements
。使用我的初始化器正确填充它。当我点击ProfileController
时,需求显示。但是,在第一个请求之后,子请求对ProfileController#completeness
的请求没有列出@requirements
。单例对象上的数组为空。我相信单例在控制器请求中不会返回相同的实例。我哪里出错了?
注意:这个类只保存需求,而不是特定用户实现这些需求的进度。需求很少改变,所以我想避免数据库查找。
# lib/profile_completeness.rb
require 'singleton'
class ProfileCompleteness
include Singleton
include Enumerable
attr_reader :requirements
def add_requirement(args)
b = Requirement.new(args)
@requirements << b
b
end
def clear
@requirements = []
end
def each(&block)
@requirements.each { |r| block.call(r) }
end
class Requirement
# stuff
end
end
# config/initializers/profile_completeness.rb
collection = ProfileCompleteness.instance()
collection.clear
collection.add_requirement({ :attr_name => "facebook_profiles",
:count => 1,
:model_name => "User",
:instructions => "Add a Facebook profile" })
class ProfileController < ApplicationController
def completeness
@requirements = ProfileCompleteness.instance
end
end
<!-- app/views/profile/completeness.html.erb -->
<h2>Your Profile Progress</h2>
<table>
<%- @requirements.each do |requirement|
complete_class = requirement.is_fulfilled_for?(current_user) ? "complete" : "incomplete" -%>
<tr class="profile_requirement <%= complete_class -%>">
<td>
<%- if requirement.is_fulfilled_for?(current_user) -%>
✓
<%- end -%>
</td>
<td><%= raw requirement.instructions %></td>
</tr>
<%- end -%>
</table>
<p><%= link_to "Profile", profile_path -%></p>
这是行不通的(多线程,不同的rails worker等),你不能指望每个请求都在同一个rails应用程序线程中着陆。如果您的服务器崩溃,所有的进度都将丢失!因此,跨请求/会话持久保存数据的方法是使用数据库。
将您的完整性跟踪器建模为一个模型并将其存储在您的数据库中。
另一个解决方案是使用Rails应用程序缓存。
设置键值对:
Rails.cache.write('mykey', 'myvalue');
阅读:cached_value = Rails.cache.read('mykey');
阅读更多关于Rails Cache的信息
如果你想要一个大数据集和快速访问的解决方案,我建议你使用redis:
这里有一篇很好的文章,特别是"使用Redis作为你的Rails缓存存储"部分,并通过"Redis相关宝石"部分查看。
重要的是键/值数据结构,我会选择像 这样的键progress:user_id:requirements = [{ ...requirement 1 hash...}, {..requirement 2 hash.. }]
您不能在Rails环境中使用单例,因为它们与单独的进程(可能有许多)是隔离的,而且在开发模式中,这些类在每次请求时都会被故意重新初始化。
这就是为什么你看到保存在它们中的任何东西都消失了。
如果您必须在请求之间持久化这样的数据,请使用session
设施。
一般的想法是创建某种可以在这里引用的持久记录,例如创建一个表来存储profilecomplecomplete记录。然后在每次请求时重新加载它,根据需要更新它,并保存更改。