Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possibility to pass optional arguments in step_to #172

Open
luizcarvalho opened this issue Mar 29, 2019 · 3 comments
Open

Possibility to pass optional arguments in step_to #172

luizcarvalho opened this issue Mar 29, 2019 · 3 comments

Comments

@luizcarvalho
Copy link
Contributor

Hello my friends,

Me again :P

During all that I used Stealth, has a functionality that I always missed. The possibility of passing a parameter to another flow action.

For example, when I work with dynamic items as a product listing. This would be my controller:

class ProductsController < BotController

  def say_products
    @products = Product.all
    send_replies
  end

  def say_product_details
    @product = Product.find(number: 1)
    send_replies
  end

end

And this, my reply.

<% if @products.count > 1  %>

- reply_type: list
  top_element_style: compact
  elements:
    <% @products.each do |product|  %>
    - title: "<%= product.name %>"
      subtitle: "🏷 <%= product.description %>"
      buttons:
        - type: "payload"
          text: 'Details'
          payload: PRODUCT_DETAILS_<%= product.number %>"
    <% end  %>

<% else  %>
<% product =  @products.first  %>

- reply_type: text
  text: |
    Name: <%= product.name %>
    Description: <%= product.description %>
    Size: <%= product.size %>
    Color: <%= product.color %>
  buttons:
    - type: "payload"
      text: 'Buy'
      payload: BUY_PRODUCT_<%= product.number %>"
    - type: "payload"
      text: 'Back'
      payload: LIST_PRODUCTS
<% end  %>

This is a little ugly to me and not reusable. I need copy and paste parte this code in product_details.yml and, every that this change, change in all other parte of project

A see a, maybe, better way to do this. If we could pass a product id with a params, and control this in controller, otherwise replies? Like this (is only a example to illustrate the case):

class ProductsController < BotController

  def say_products
    @products = Product.all
    if @products.count > 1
      send_replies
    elsif @products.count = 1
      step_to action: :say_product_details, params: { product_id: @products.last.number }
    else
      step_to action: :say_no_products
    end
  end

  def say_product_details
    @product = Product.find(number: 1)
    send_replies
  end

  def say_no_products
    send_replies
  end

end

Some like this. Controller would orchestrate information and replies are only responsible for formatting them, and thus would better separation of responsibilities.

say_products.yml.erb only this:

- reply_type: list
  top_element_style: compact
  elements:
    <% @products.each do |product|  %>
    - title: "<%= product.name %>"
      subtitle: "🏷 <%= product.description %>"
      buttons:
        - type: "payload"
          text: 'Details'
          payload: PRODUCT_DETAILS_<%= product.number %>"
    <% end  %>

And say_product_details.yml.erb only this.

- reply_type: text
  text: |
    Name: <%= product.name %>
    Description: <%= product.description %>
    Size: <%= product.size %>
    Color: <%= product.color %>
  buttons:
    - type: "payload"
      text: 'Buy'
      payload: BUY_PRODUCT_<%= product.number %>"
    - type: "payload"
      text: 'Back'
      payload: LIST_PRODUCTS
@luizcarvalho
Copy link
Contributor Author

Another benefit of this feature is more powerful and contextual messages to CatchAll system.

CatchAll scheme is a awesome to retry and limit wrongs inputs of the users, but your messages are very generics, to all cases. If we could pass the error as parameter, the bot will be able to respond more efficiently and contextually.

We could create validations that raise exceptions and for each exception return respective message with useful information.

  def get_product_number
    validate(@current_message.message)
   #  raise length error: The number should be more than 10 characters 
   #  raise format error: Oh... this need be a number
   #  raise includes error: category need be shoes, t-shirt or hat.
   #  etc etc etc
    send_replies
  end

And in run_catch_all we can pass the error type.

    def run_catch_all(reason: nil, error: nil)
        error_level = fetch_error_level
        Stealth::Logger.l(topic: "catch_all", message: "CatchAll #{calculate_catch_all_state(error_level)} triggered for #{error_slug}: #{reason}")

        if defined?(CatchAllsController) && FlowMap.flow_spec[:catch_all].present?
          catch_all_state = calculate_catch_all_state(error_level)

          if FlowMap.flow_spec[:catch_all].states.keys.include?(catch_all_state.to_sym)
            step_to flow: 'catch_all', state: catch_all_state, params: error
          else
            # We are out of bounds, do nothing to prevent an infinite loop
            Stealth::Logger.l(topic: "catch_all", message: "Stopping; we've exceeded the number of defined catch_all states.")
            return false
          end
        end
      end

And in our catch_all_controller.rb we can take error message easily

  def level1
    @error_message = fetch_error_message(error)
    send_replies

    if fail_session.present?
      step_to session: fail_session
    else
      step_to session: previous_session - 2.states
    end
  end

@bhtabor
Copy link

bhtabor commented Aug 2, 2019

Perhaps #183 can work for you.

@luizcarvalho
Copy link
Contributor Author

Works fine!! Thanks @bhtabor

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants