fredjapan
fredjapan

Reputation: 3

Conditional chained methods based on param (Ruby on Rails)

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

Answers (1)

Benjamin Alijagić
Benjamin Alijagić

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

Related Questions