我遇到了一个奇怪的问题,寻找可以到达的最佳解决方案。我正在开发一个rails应用程序,它显示来自另一个应用程序(nodejs)正在使用的公共数据库的数据。所有CRUD操作都发生在另一个平台上。在rails应用程序中,我们只查询并显示数据。
在rails app中,我需要自动更新视图而不刷新。例如
def index
@states = State.page(params[:state_page])
@level_one_companies = Company.includes(:state)
.where(level: 1)
.order('created_at DESC').limit(20)
@level_two_companies = Company.includes(:state)
.where(level: 2)
.order('created_at DESC').limit(20)
end
在索引页面上,我将为每个表格提供表格,当新数据添加到州(或)第1级(或)第2级公司时,我需要刷新表格。
我知道我可以通过两种方式自动更新视图,例如
通常在使用Action Cable时,我们将在db中创建记录后从服务器广播数据(在create action(或)after_save回调模型之后的.save之后)。但是,我没有通过rails app创建任何记录。
我的第一个问题是,在这种情况下有没有办法使用动作电缆?。
所以我选择了第二个选项并且工作正常。但它每隔X秒就会进行过多的db调用。 有没有办法减少查询以更新视图? 我能和这里一起去的最佳方式是什么?任何帮助高度赞赏。谢谢。
答案 0 :(得分:3)
如果您的代码设置正确,则您将postgres用作数据库。
postgres提供了一个发布 - 订阅机制,您可以将其与action-cable结合使用,以便收听数据库中的更改。
在this gist中,您可以找到带有server-sent-events的postgres-pubsub的示例。将其转换为动作电缆兼容代码应该很简单。
答案 1 :(得分:0)
您可以在桌面上创建触发器(创建/更新/删除)以在"频道"上触发通知,并且您可以收听所述频道的事件。我使用socketcluster,听取工作人员的意见,并向消费者(浏览器和移动应用程序)广播。
首先创建触发器:
CREATE FUNCTION deletes_notify_trigger() RETURNS trigger
LANGUAGE plpgsql
AS $$
DECLARE
BEGIN
PERFORM pg_notify('deletes_channel', ('DELETED' || ';;' || OLD.id )::text );
RETURN new;
END;
$$;
和
CREATE TRIGGER deletes_trigger AFTER DELETE ON events FOR EACH ROW EXECUTE PROCEDURE deletes_notify_trigger();
你可以在正在广播的数据包中添加你想要的任何东西,在我的情况下我只需要记录的ID。对于创建和更新,您可以发送完整行或仅发送一些选定列。您也可以在PG 9.2(我认为)和更高版本中将其作为JSON发送。我使用9.1,所以我连续使用;;分隔符。
确保您的代码在查询之间最多占用10%的时间,否则如果您执行复杂的连接或更新或其他操作,您会发现性能会显着下降。您希望它尽可能简单快速,将其保持在基本操作中,并对应用程序层进行任何繁重的工作。
然后,观察者和广播给消费者(在我的情况下节点,socketcluster和pg gem,在你的情况下你可以使用JS,Python,Ruby,无论你喜欢什么)
var global_deletes = socket.subscribe('deletes_channel');
pg.connect(connectionString, function(err, client) {
client.on('notification', function(dbmsg) {
console.log(dbmsg.payload);
var payload = dbmsg.payload.split(";;"); // you can use JSON instead
if (payload[0] == "DELETED") { // when a DELETE is received...
global_deletes.publish(dbmsg.payload);
var tchannel = socket.subscribe('events-'+ payload[1]); // join the channel we want to broadcast
setTimeout( () => tchannel.publish(dbmsg.payload), 50); // send the update to all consumers
setTimeout( () => tchannel.unsubscribe(), 100);
}
);
var query = client.query("LISTEN deletes_channel"); // turn on notifications from the server
});