Bookstore — Final Implementation-9
QuickHotSeries — Lightning-Fast Insights, Now in Version 9
In this episode, we’ll automatically update the entire interface using Turbo Stream.
Let’s Get Started!
Note: if you get stuck, please see my repo.
1.Create Book
Model:
app/models/book.rb
after_create :create_chart
private
def create_chart
broadcast_append_to('books_charts_channel', partial: '/dashboard/charts/books/chart', locals: { book: self }, target: 'books_charts')
end2.Book & Chart Partials
app/views/dashboard/charts/books/_books.html.erb
<section class="flex flex-col w-full border">
<h3 class="font-bold text-lg">Sells By Book</h3>
<div class="flex flex-col" id='books_charts'>
<% Book.all.each do |book| %>
<%= render 'dashboard/charts/books/chart', book: book %>
<% end %>
</div>
</section>app/views/dashboard/charts/books/_chart.html.erb
<div data-controller="book" data-book-sells="<%= latest_sells(book.id) %>" data-book-id="<%= book.id %>" data-book-name="<%= book.name %>" id="book_<%= book.id %>" >
<canvas id="book_chart_<%= book.id %>" style="width:100%;max-width:700px"></canvas>
</div>3.Streaming from Tag: Two Channels
app/views/dashboard/index.html.erb
<%= turbo_stream_from 'books_charts_channel' %>
<%= turbo_stream_from 'sells_charts_channel' %>4.Real-Time Updates: Broadcasting in the Model for Book Sales
app/models/sell.rb
after_create_commit :update_charts
private
def update_charts
broadcast_replace_to('sells_charts_channel', partial: '/dashboard/charts/days/chart', locals: {}, target: 'days_chart')
broadcast_replace_to('sells_charts_channel', partial: '/dashboard/charts/revenue/chart', locals: {}, target: 'revenue_chart')
broadcast_replace_to('sells_charts_channel', partial: '/dashboard/charts/books/chart', locals: { book: book }, target: "book_#{book.id}")
endThe after_create_commit :update_charts line sets up a callback that triggers the update_charts method after a record is successfully created in the database.
In update_charts:
broadcast_replace_to: This method sends updates to a specified channel (sells_charts_channel) to refresh specific chart components on the client side.- Partial Views: It uses three partial views to render updated charts:
'/dashboard/charts/days/chart': Updates the daily sales chart.'/dashboard/charts/revenue/chart': Updates the revenue chart.'/dashboard/charts/books/chart': Updates the chart for a specific book, using the book instance to pass its data.
This approach ensures that the charts reflect the latest data immediately after a new sell is recorded.
Get J3’s stories in your inbox
Join Medium for free to get updates from this writer.
5.Confirming all the view & chart partials & index
app/views/dashboard/charts/days/_chart.html.erb
<div data-controller="days" data-day-sells="<%= sells_per_day %>" id="days_chart">
<canvas id="daySells" style="width:100%;max-width:700px"></canvas>
</div>app/views/dashboard/charts/days/_days.html.erb
<section class="flex flex-col w-full border">
<h3 class="font-bold text-lg">Sells Per Day</h3>
<%= render 'dashboard/charts/days/chart' %>
</section>app/views/dashboard/charts/revenue/_chart.html.erb
<div data-controller="revenue" data-revenue-sells="<%= revenue_from_sells %>" id="revenue_chart">
<canvas id="revenueSells" style="width:100%;max-width:700px"></canvas>
<table class="my-5 w-full border-collapse border-2">
<thead>
<tr class="bg-indigo-200 text-indigo-800">
<th class="w-1/3 border-2 px-4 py-2 text-sm text-center font-semibold">ID</th>
<th class="w-1/3 border-2 px-4 py-2 text-sm text-center font-semibold">Name</th>
<th class="w-1/3 border-2 px-4 py-2 text-sm text-center font-semibold">Revenue</th>
</tr>
</thead>
<tbody>
<% Book.includes(:sells).find_each do |book| %>
<tr class="even:bg-indigo-50">
<td class="w-1/3 border-2 px-4 py-2 text-sm text-center"><%= book.id %></td>
<td class="w-1/3 border-2 px-4 py-2 text-sm text-center"><%= book.name %></td>
<td class="w-1/3 border-2 px-4 py-2 text-sm text-center font-semibold">
<%= number_to_currency(book.sells.sum(:total), unit: "USD ") %>
</td>
</tr>
<% end %>
</tbody>
</table>
<div class="mt-4 p-4 text-lg font-bold text-indigo-800 border-t-2">
Total Revenue: <%= number_to_currency(Sell.all.sum(:total), unit: "USD ") %>
</div>
</div>app/views/dashboard/charts/revenue/_revenue.html.erb
<section class="flex flex-col w-full border">
<h3 class="font-bold text-lg">Revenue</h3>
<%= render "dashboard/charts/revenue/chart" %>
</section>app/views/dashboard/index.html.erb
<%= turbo_stream_from 'sells_charts_channel' %>That’s all Folks!
Thank you!
If you enjoyed it, please hit the applause button to help others see this. Thanks!
Let me know if you need any further clarification! We’re striving to make this tutorial as clear as possible.
In the next episode, we’ll tackle timestamps. Currently, our database records days as strings, which isn’t ideal for production, right?
Credits & References
Ruby on Rails 7 y Hotwire — 2023 in Desarrollo de aplicaciones de Ruby on Rails utilizando Hotwire, Turbo Frames, Turbo Streams y Stimulus JS.
Related Posts
Note: Database Renewal
Ubuntu Terminal
docker compose restartVscode Terminal
rails db:drop
rails db:migrate
rails s -b 0.0.0.0 -p 3001
# Enter a new User








