Reputation: 3
I'm building a goal app and I have a view which changes based on a url parameter depending on if the goals are "weekly" "quarterly" or "yearly".
I have some code in my view where I use those two methods at different places: beginning_of_week & end_of_week (in the case of weekly goals).
Now if I'm on my quarterly goals, I'd like to use: beginning_of_quarter and end_of_quarter instead... (and same for yearly goals).
Therefore, I was thinking to create 2 methods: beginning_of_term and end_of_term which would call the appropriate method depending on the "horizon" parameter in the URL (e.g. horizon=week).
To do so though, I'm not really sure how to do. I tried writing a helper but it didn't work with chained methods...
Here is the code in my view:
<% @goals.group_by{ |u| u.date.beginning_of_week}.sort.reverse.each do |term_start, goals|%>
<div id="term-group" class="container">
<%= form_with model: @goal, url: edit_multiple_goals_path, local: true, method: :get do %>
<hr/>
<div class="level">
<div class="level-left">
<h2 class="subtitle level-item">
<% if DateTime.current.to_date.beginning_of_week == term_start %>
This <%= @horizon %>
<% elsif DateTime.current.to_date.beginning_of_week + 1.week == term_start %>
Next <%= @horizon %>
<% else %>
Previous <%= @horizon %> ~ <%= term_start.end_of_week %>
<% end %>
</h2>
</div>
<!-- MORE CODE -->
Thank you very much for your help.
Upvotes: 0
Views: 100
Reputation: 38
From what I see you're looking for a way to call methods dynamically.
In order to make that possible you can use send
and interpolate your variable into the string.
DateTime.current.to_date.send("beginning_of_#{@horizon}")
Send invokes the method by name we defined as a string. Just as if you wrote:
DateTime.current.to_date.beginning_of_week
Read more about how it works: https://apidock.com/ruby/Object/send.
Also, since @horizon
is URL param, something easily modified by anyone, you will need to validate it and make sure nothing except week/month/quarter/year
passes.
if %w(week month quarter year).include? @horizon
# render view
else
# error
end
You could also use respond_to?
to make sure your dynamic method actually exists.
DateTime.current.to_date.respond_to?("beginning_of_#{horizon}")
Most of this code doesn't really belong into a view. I would suggest extracting it in a helper that accepts horizon as argument and returns adjusted date. Just a rough idea:
def beginning_of_term(horizon)
current_date = DateTime.current.to_date
method_name = "beginning_of_#{horizon}"
if current_date.respond_to?(method_name)
current_date.send(method_name)
end
end
Upvotes: 1