Turbo Streams

Actions and Targets

An example on how turbo_stream is rendered:

= turbo_stream.append :messages, @message

Where :messsages is the target and @message renders the partial _message.html.haml. Then it is rendered to:

<turbo-stream action="append" target="messages">
  <template>
    <div id="message_23">
      // This div will be append to element with id="messages"
    </div>
  </template>
</turbo-stream>

7 possible Actions

  • APPEND: Appends template to target
  • PREPEND: Preppends template to target
  • REPLACE: Replaces the full target with template
  • UPDATE: Replaces the content of target with template
  • REMOVE: Removes target
  • BEFORE: Adding template before target element
  • AFTER: Adding template after target

Streaming from HTTP responses

In rails controller streams will be rendered like:

def create
  @message = Message.find(....)
 
  respond_to do |format|
    format.turbo_stream # renders template in: create.turbo_stream.haml
    format.html { redirect_to messages_url }
  end
end

Reusing server side templates inline:

  format.turbo_stream do
    render turbo_stream: turbo_stream.append(:messages, 
                partial: "messages/message", locals: { message: @message})
  end

Both “partial:” and “locals:” can be replaced by @message (Great Rails code!!!).

Some notes

RECOMENDATION: Good practice is design without Streams, then in poor connections or server issues, when web sockets are broken, it will run anyway. Like a browser without JavaScript.
NOTE FOR BROWSER CACHE: Attribute “data-turbo-permanent” makes element alwaiys the samen in browser cache.

Defining a Smart Contract Lifecycle in Solidity

address owner;
bool public paused;
constructor() public {
  owner = msg.sender;
}
function setPaused(bool _paused) public {
  require(msg.sender == owner, "you are not authorized for this action");
  pause = _paused;
}

First on DEPLOYMENT you want to be sure that the owner is the only who interacts with the contract for concrete actions:

  • Address of deployer is the owner
  • constructor(): initializes contract class
  • setPaused(): pause control of contract
  • require(): basic owner authorization
function withdrawAll(address payable _to) public {
  require(msg.sender == owner, "you are not authorized for this action");
  require(!paused, "Contract is paused!");
  _to.transfer(address(this).balance);
}

Second during the LIFECYCLE, you can make any actions on contract balance:

  • require(sender): checks auth
  • require(paused): checks if contract is suspended
  • address(this): gets address of this contract
  function destroy (address payable _to) public {
    require(msg.sender == owner, "you are not authorized for this action");
    selfdestruct(_to);
  }

Last, you can disable a contract by selfdestructing and sending balance to any address the owner wants.

Ethereum addresses in Solidity

ETH addresses are hexadecimal like: 0x123AFD… The same addresses can be owned by a wallet or by Smart contract deployment. So you can send and get balance of both.

Basic functions are:

  • address.balance: total weis in account (1 ETH == 10^18 weis).
  • address.transfer(amount): send an amount in weis, raising an exception if error.
  • address.send(amount): returns true if success instead of raising an exception.

Transfer/send costs are 2300 in gas.

Global objects in a contract are:

  • msg.sender: Sending address
  • msg.value: weis sent
  • now: current timestamp

Functions or addresses should be marked as PAYABLE to receive ETH.