Using turbostreams in Rails to re-render a partial using a collection that depends on a date range set within the controller - ruby-on-rails

I'm trying to add live update functionality to a statistics page using Turbo.
The page has a user-set date range with a simple filter using url params.
The value of each stat is determined by summing values of a collection of objects (matched by the date range).
Everytime an object updates in the db, the stats need to refresh if they relate to this object (i.e. the object has a date_created within the date range that the user has selected on the filter).
In the controller
#things = Thing.where(:created_at => params[start_date]..params[end_date])
In the view
<%= turbo_stream_from "profit" %>
<%= render 'profit_card', things:#things %>
The rendered partial (profit_card)
Total Profit: <%= things.sum(&:profit) %>
What I would like to add to the Thing model is
after_update_commit { broadcast_replace_to "profit", partial: "profit_card", locals: {things: ???} }
The problem is that there is no way of putting the right collection #things into the above line. The specific #things are filtered in the controller depending on the date range selected.
If the filter only selected a single date (and not a range), this could be done like this:
broadcast_replace_to "profit_#{thing.created_at}", partial: "profit_card", locals: {Thing.where(created_at: self.created_at)}
And then in the view
<%= turbo_stream_from "profit_#{selected_date_from_params}" %>
This however doesn't work with date ranges, as there are too many combinations.
Is there another way to achieve this functionality using turbo?
Thanks very much!

Related

Active Records - List the item's index number (the actual order number in which the item is displayed)

I'm a newb to Ruby on Rails and I have a issue trying to display the index number of a record set. I've had a good search, but can't find the specific answer.
The issue I'm having is that I cannot find a way to output the index number from a recordset which i'm displaying.
[Title], [Description]
[Title], [Description]
[Title], [Description]
etc.
So to clarify, I'm looking to output the order (index) number (1, 2, 3) in a list where i'm able to output the Title & Description, also i'll point out the obvious - this is different to the unique ID which may be stored in the database, thus if i was to filter or sort the results I would still want to show the order (index) number (1, 2, 3 etc).
I have founds example of where they loop through the results and incrementally add to a pre-defined index value. The problem is my app doesn't use a loop statement to output the records, instead it's using an Active Record to display (and essentially loop through) the results. From what I understand, Active records will automatically loop through and output the records by rendering the code snippet ie. <%= render #links %> This works great for my example - For the full code for the app, please refer to the tutorial I deprived the app from:
https://www.codementor.io/danielchinedu/building-a-basic-hacker-news-clone-with-rails-5-4gr4hrbis
So in retrospect, I'm looking to clone the app in the tutorial but add an order number to the link lists.
From the documentation:
Rails also makes a counter variable available within a partial called
by the collection, named after the member of the collection followed
by _counter.if you're rendering #products, within the partial you can
refer to product_counter to tell you how many times the partial has
been rendered.
guides.rubyonrails.org
So you can use something like <%= link_counter %> in your _link.html.erb partial. Hope this will help.
The tutorial actually explains it quiet well, i think.
Underneath the <%= render #links %>:
We are using a rails feature here, when you call render on an instance variable holding an active record relation object, it will iteratively loop through the object and then render the appropriate partial.
So! It's a Rails feature making it easier to write partial loops!
<%= render #links %> is the same as: <%= render partial: 'link', collection: #links %>
If you want an index in your partial, you can just append a local variable. For example:
<%= render #links, locals: {num: 1} %>
And then in your view after you have written the variable, remember to add 1 so it's ascending.
<div class="link">
<div class="title">
<%= num %>
<%= link_to link.title, (link.url? ? link.url : link) %>
...
<% num += 1 %>
Good luck!

How do I pass an incrementing counter into a partial when not rendering from an instance variable?

I have a partial: views/nodes/_node.html.erb, which I render on any view like so:
<%= render #nodes %>
When I render it like that, per the Rails Guides, I can use node_counter within the partial as a counter to keep track of various elements within the partial (or say assign an ID that increments every time the partial is rendered).
Now I want to use this same partial, but not rendered like that but rather like this:
<%= render partial: "nodes/node", locals: {node: event.eventable} %>
When I do that, I get this error:
undefined local variable or method `node_counter' for #<#<Class:0x007fa3b6ca9778>:0x007fa3b58a60c8>
That is because I never specified/passed node_counter as a local variable.
So how do I specify node_counter to start at 0 and always increment every time this partial is rendered - if I can't do it the Rails Way?
For reference, the Rails Guide says this:
Rails also makes a counter variable available within a partial called by the collection, named after the member of the collection followed by _counter. For example, if you're rendering #products, within the partial you can refer to product_counter to tell you how many times the partial has been rendered. This does not work in conjunction with the as: :value option.
In your calling view, you can use each_with_index:
<% #foo.each_with_index do |foo, index| %>
<%= render 'nodes/node', f:foo, node_counter:index %>
Then in your _nodes/node partial, node_counter will increment starting at 0.
The reason that node_counter is not available for you in your second call is that you are calling the partial with a member, not a collection.

Rails and factory patterns

Imagine a Rails project that looks up animal celeberties based on their names. This Rails app is backed by an external service that does the actual lookup. The service returns back results based on a key. For example, if I make a request to this external api like [GET] /animal?name=benji, I would get back something like {"type":"dog", "legs":"4", "tail-length":"short", "collar":"blue"}. However, if I pass in ...?name=flipper to the animal endpoint, I would get back {"type":"dolphin", "color":"gray", "food":"fish"}. (The data is returned in actual JSON or XML. I am just using pseudo code here to communicate the point.)
My first question is this... Given that the attributes of the return call vary based on data which is passed in, when unmarshaling a response (for lack of a better term) into a "model" object, does it make sense to implement some type of factory pattern (ala Design Patterns in Ruby, by Russ Olsen, Chapter 13) to create objects of an appropriate class? Are there other approaches that would make sense?
My next question is this, lets say that I want to display a list of all animals on a web page (using ERB templates.) Does it make sense to create different partial templates (eg _dolphin.html.erb and _dog.html.erb) and then put a case in the main list view that can deligate rendering each list item to an appropriate template.
For example:
list.html.erb...
<ul>
<% for animal in #animals.each %>
<li>
<% if animal.type == 'dog' %>
<%= render :partial => 'dog', :locals => {:animal => animal} %>
<% elsif item.type == 'dolphin' %>
<%= render :partial => 'dolphin', :locals => {:animal => animal} %>
<% else %>
<%= render :partial => 'generic_animal', :locals => {:animal => animal} %>
<% end %>
</li>
<% end %>
</ul>
(Here animal.type=='dog' is intentional. I am not using a symbol (:dog) because the data returned back from the API is a string value, and it is used to populate the animal.type attribute. Bad, I know.)
The project that I am working on is using this approach right now. (Obivously, I have changed the elements/domain.) I am wondering if this is a valid approach, and/or if others have dealt with similar problems and how they went about it.
Thanks!
I'd say create a single model and a single view which contains all possible attributes (can't be an infinite number ;) ).
And then you have an
if attribute_x exists then
display it
end
if attribute_y exists then
display it
end
for each attribute.
If you create a view for each animal this wouldn't be DRY at all, 'cause you'll repeat yourself sooo many times, just knowing that each animal has favorite food and a color, etc.. Another reason: If the API changes a bit, and an animal gathers or looses an attribute you would have to adapt this change.
With just one view, it would be all fine for all time.
If you want to be super-sure that you gather all attributes, you could place an array of all known attributes inside your controller and if there's something unknown: write it to a log file.
I'd only choose the way of 'one view per animal' if you want to be able to display things completely different for some animals. But then you could also tell your controller that it should choose another view if name = 'Donkey Kong'. you know what I mean.

Ruby on Rails - Passing values to a link_to

I'm a RoR beginner and am using Rails 3.2.3.
I have a search form on my page and it performs a get request and filters the results correctly.
I want to add the possibility of also searching Products by dates.
I inserted a date_select and am able select the date and when the page refreshes after the search, the chosen dates are still there on the date_select, as I am able to get them through params.
However, my issue is that when the page renders the products, they have a link_to to their show action.
My goal is to also pass alongside the url the dates that were selected to perform the search on that link_to.
For ex, if the user selects a date of 20-06-2012 to 25-06-2012 it only shows products inserted on that time frame (and all those params are on the url)
But the link to show action of each displayed product is only:
link_to <%= link_to product.name, product%>
which renders
http://localhost:3000/products/24 (por example)
what I want to render/show is something like:
http://localhost:3000/products/24?from=20-06-2012&to=25-06-2012
The selected dates to perform the search are not stored in the database at this moment, but I will need to get them from the URL on a latter page, therefore, both dates will need to be preserved through 2 different pages before the users fills a form and then those dates are inserted in the DB.
Any tips on this? I've searched but all I found was on how to pass variables that exist in the model and I do not want to use cookies nor session variables.
Thanks in advance,
Regards
If you want to pass arbitrary parameters to the following call
<%= link_to product.name, product %>
you need to invoke the path method explicitly instead of using the implicit version. The line above is equivalent to
<%= link_to product.name, product_path(product) %>
Then you can pass parameters
<%= link_to product.name, product_path(product, :from => 'whatever', :to => 'whatever') %>
Can you try like this
link_to <%= link_to product.name, product, :param_you_want => "value you want" %>
Now you can set value in "param_you_want" as you wish.
But in my case set value in it "value you want"
Hope you can get idea

Rails Dependent Form - Selecting a Specific Item from a Model

I'm new to Rails so be gentle. I've got a model, 'Event', with the the following information: 'sport', 'home_team', 'away_team', and 'time' in datetime.
Now I want to enable the user to 'follow' a specific event and am trying to find the best way to do so. Ideally, I'd like a form with dependent drop down lists. For example, the user first picks a 'day', then a 'sport', then selects from a relevant list of 'events' of that 'day' and 'sport'. This association is then stored in a rich join table called 'following'.
I've seen tutorials on complex forms that involve multiple models, but what about when everything is from the same model? How do build a form to grab a handful of relevant records. I only have a few distinct values for 'sport', so I wasn't sure it made sense to give it its own model. And can I easily get events on a certain date from a 'datetime' value?
There a lot of ways to go about this, here is one option:
Since you want to see multiple events, you'd probably start off focused on the index action. Start off by creating and index action, but add some hooks to filter it, i.e.
def index
if params[:sport]
#events = Event.where("sport = ?",params[:sport])
else
#events = Event.all()
end
end
Now, if you've defined your routes like this:
resources :events
You'll have a a route /events that will accept a get request and route you to the index action.
But if you want a form where you can select things, a form will by default POST, but you could create a form that GETs to '/events'
i.e. in app/views/events/index.html.erb
<%= form_tag '/events', :method=>:get %>
Then, you want to create your form elements that will send the params.
i.e.
<%= select_tag 'sport', '<option>baseball</option><option>football</option>' %>
Put in a submit button
<%= submit_tag 'See Events'
Then 'end' your form with
<% end %>
Now when you click on the 'See Events' button, you will send a get request to the route '/events', and the 'sport' parameter will show up in the index action, filtering the events.
To keep things simple and all in the index view, after your form you'd list all the events.
<% #events.each do |e| %>
Sport: <%= e.sport %><br/>
Home Team: <%= e.home_team %><br/>
Away Team: <%= e.away_team %><br/>
Time: <%= e.time.strftime('%H %M') %><br/>
<% end %>

Resources