0

I have this a custom action in Task controller, which has if else

statements and returns Api calls from Safe browsing api, which I need to render to users

in index.html.erb without refreshing the page. I've tried Ajax but it doesn't seem to

work correctly.In addition, I've tried to search and follow some Hotwire and Turbo

tutorials but they seem to solve complicated problems unlike my problem.

My problem and solution are simple, a user submits link to the server to be checked by

Google Safe Browsing API and return results back to the user rendered in the same

page without refreshing. I currently have them rendered in a different page by using

for example

render plain: "" and return

Finally, this's my code and I need a simple solution to render the custom action results

to users without refreshing the page.

This's check_url action in tasks_controller.rb

def check_url
    @id = params[:id]
    @result = params[:result]
    if params[:link].present?
      api_key = ENV[""]
      # Set up the request parameters
      url = params[:link]

      formatted_url = canonicalize_url(url)

      threat_types = ["MALWARE", "THREAT_TYPE_UNSPECIFIED", "SOCIAL_ENGINEERING", "UNWANTED_SOFTWARE", "POTENTIALLY_HARMFUL_APPLICATION"]
      platform_types = ["ANY_PLATFORM"]
      body = {
        client: {
          clientId: api_key,
          clientVersion: "1.0.0",
        },
        threatInfo: {
          threatTypes: threat_types,
          platformTypes: platform_types,
          threatEntryTypes: %w[URL THREAT_ENTRY_TYPE_UNSPECIFIED EXECUTABLE],
          threatEntries: [
            { url: formatted_url },
          ],
        },
      }

      # Set up the request headers
      headers = {
        "Content-Type" => "application/json",
      }

      # Make the request to the Safe Browsing API
      response = HTTP.post(
        "https://safebrowsing.googleapis.com/v4/threatMatches:find?key=",
        json: body,
        headers: headers,
      )

      # Check the response
      if response.code == 200
        data = JSON.parse(response.body)
        puts JSON.pretty_generate(data)

        @result = response.body
        if data["matches"].try(:empty?)
          render plain: "The URL is safe" and return
        else
          render plain: "The URL is not safe" and return
        end
      else
        render plain: "An error occurred"
      end
    else
      puts "link variable is empty"
    end

    puts "Response code: #{response.code}"
    puts "Response body: #{response.body}"

    puts "Request parameters: #{body}"
    puts "Request headers: #{headers}"
  end

  private

  def task_params
    params.require(:task).permit(:link, :result)
  end

  
end

This's the submission form in _form.html.erb

<%= form_tag("/check_url", method: "post") do %>
  <%= label_tag(:link, "Enter a link:") %>
  <%= text_field_tag(:link) %>
  <%= submit_tag("Submit") %>
<% end %>

This's index.html.erb

<% if notice.present? %>
  <p class="py-2 px-3 bg-green-50 mb-5 text-green-500 font-medium rounded-lg inline-block" id="notice">
    <%= notice %>
  </p>
<% end %>
<h1 class="font-bold text-2xl">Task Manager</h1>
<div class="mt-4">
  <%= render "form", task: @task %>
  <%= render 'tasks/check_url' %>
</div>

Thank you all and please ask any questions or requests, I'm new to Ruby on

Rails and want to grasp it.

Nasser FN
  • 59
  • 8
  • You could use stimulus to update the page, that's one thing it's meant to do. Or you can do an AJAX submit->update. What did you try as far as an AJAX solution? The process for AJAX is usually a submit that has `remote: true`, then in your action you render a JS response that renders a .js file, and that JS file will update the relevant page. – Beartech Jan 01 '23 at 21:28
  • Here is an old but still relevant article: http://www.korenlc.com/remote-true-in-rails-forms/ – Beartech Jan 01 '23 at 21:28
  • But it seems like Hotwire and Turbo should easily do what you want. Have you tried using a sample Hotwire example and substitute your relevant code into it to see how it would work? – Beartech Jan 01 '23 at 21:30
  • I followed some Hotwire and Turbo tutorials to substitute but they aren't as the same as my problem since I have multiple if statements in check_url action that need to be rendered to users.I'll check the link you provided and see how it goes. Thank you – Nasser FN Jan 01 '23 at 21:44
  • I think you should rethink all of those "renders" in your multiline if statement. You can still do what the article advises but you'll just be repeating yourself a lot. Why not pass the result into a variable and render that? Also I'd move all of that out of the controller and into instance methods in the model. Your controller should call a method on the input, get a result, and render that result via JS back to the page. – Beartech Jan 01 '23 at 22:02
  • And you are rendering `check_url`, I would not do that. I would just put a `
    ` on the page. As users submit the form with `remote: true` you would append the results to the "checked_urls" div. I am not familiar with Hotwire/Turbo yet so I can't give you better advice on that.
    – Beartech Jan 01 '23 at 22:06
  • I tried Ajax for few days with no success and then I suddenly landed at this link which explains Hotwire and its power.Finally, I used Turbo streams with no JS and it really solved my problem.Thank you so much for the advise, Beartech! https://www.bootrails.com/blog/rails-7-hotwire-a-tutorial/ – Nasser FN Jan 16 '23 at 03:42

0 Answers0