2017-10-13 74 views
5

我遇到了一个奇怪的问题,寻找我可以到达的最佳解决方案。我正在开发一个rails应用程序,它显示来自另一个应用程序(nodejs)正在使用的公用数据库的数据。所有CRUD操作都发生在另一个平台上。在rails应用程序中,我们只是查询并显示数据。有什么方法可以在不查询/减少查询的情况下了解数据库更新?

在rails应用程序中,我需要自动更新视图而无需刷新。例如

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级(或)二级公司。

我知道我可以用两种方式自动更新的观点去即

  1. 作用电缆。
  2. 使用Jquery以一定的时间间隔数据池。

通常在使用Action Cable时,我们将在db中创建记录(在创建操作(或模型中的after_save回调之后的.save之后)之后从服务器广播数据。但是,我不通过Rails应用程序创建任何记录。

我的第一个问题是,在这种情况下是否有任何方式使用动作电缆?

所以我去了第二个选项,它工作正常。但是在每X秒后它会调用太多的db调用。 有什么办法可以减少查询来更新视图? 什么是我可以在这里与最好的方式?任何帮助高度赞赏。谢谢。

回答

3

如果您的标签设置正确,您将使用postgres作为数据库。

postgres提供了一个发布 - 订阅机制,您可以结合使用action-cable来监听数据库中的更改。

this gist,你可以找到postgres-pubsub与服务器发送事件的例子。将其转换为兼容行动电缆的代码应该很简单。

+0

谢谢@phoet ,会试一试,让你知道。 –

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宝石,你的情况,你可以使用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 
}); 
相关问题