I have a rails app where i am implementing search with some parameters. I have a Product model which has two parameters State and City, and on the home page i have a search form with the same parameters State and city. The logic is if a user search about a particular product in a particular State and City he will see the results of Products with the same State and City.
The site is live on Heroku (This is the app) and works well on my laptop but on mobile devices i am getting this error, this error only appears on mobile devices while selecting State:
Failed to submit error Unauthorized
I checked the log and got this
2019-05-19T11:29:09.982781+00:00 app[web.1]: [2571fe96-0174-4c3f-bc2c-a3bbe126bf55] Started POST "/get_cities_by_state" for 47.15.193.135 at 2019-05-19 11:29:09 +0000
2019-05-19T11:29:09.984478+00:00 app[web.1]: [2571fe96-0174-4c3f-bc2c-a3bbe126bf55] Processing by ProductsController#get_cities_by_state as JSON
2019-05-19T11:29:09.984857+00:00 app[web.1]: [2571fe96-0174-4c3f-bc2c-a3bbe126bf55] Parameters: {"state"=>"1"}
2019-05-19T11:29:09.985638+00:00 app[web.1]: [2571fe96-0174-4c3f-bc2c-a3bbe126bf55] Completed 401 Unauthorized in 1ms (ActiveRecord: 0.0ms)
2019-05-19T11:49:06.438325+00:00 heroku[router]: at=info method=POST path="/get_cities_by_state" host=powerful-reef-70297.herokuapp.com request_id=551700ff-038b-40e9-ad8d-7cb35f7ff7ca fwd="47.15.193.135" dyno=web.1 connect=0ms service=8ms status=401 bytes=678 protocol=https
2019-05-19T11:49:06.433346+00:00 app[web.1]: [551700ff-038b-40e9-ad8d-7cb35f7ff7ca] Started POST "/get_cities_by_state" for 47.15.193.135 at 2019-05-19 11:49:06 +0000
2019-05-19T11:49:06.437059+00:00 app[web.1]: [551700ff-038b-40e9-ad8d-7cb35f7ff7ca] Processing by ProductsController#get_cities_by_state as JSON
2019-05-19T11:49:06.437115+00:00 app[web.1]: [551700ff-038b-40e9-ad8d-7cb35f7ff7ca] Parameters: {"state"=>"2"}
2019-05-19T11:49:06.437883+00:00 app[web.1]: [551700ff-038b-40e9-ad8d-7cb35f7ff7ca] Completed 401 Unauthorized in 1ms (ActiveRecord: 0.0ms)
My products form
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<%= render 'welcome/sub' %>
<%= form_with(model: product, local: true) do |form| %>
<% if product.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(product.errors.count, "error") %> prohibited this product from being saved:</h2>
<ul>
<% product.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-style-5">
<form>
<fieldset>
<legend><span class="number">1</span> General Info</legend>
<%= form.text_field :name, id: :product_name, placeholder: "Add name of your product or service here" %>
<%= form.text_area :description, id: :product_description, placeholder: "Full Description" %>
<label for="job" style="color:#000;">Images:</label>
<%= form.file_field :image, id: :product_image %>
<%= form.file_field :imagetwo, id: :product_image %>
<%= form.file_field :imagethree, id: :product_image %>
</fieldset>
<fieldset>
<legend><span class="number">2</span> Additional Info</legend>
<label for="job" style="color:#000;">Categories:</label>
</fieldset>
<fieldset>
<%= form.select :state, options_for_select([["Select a state",""]] + State.all.map { |c| [c.name, c.id] },selected: product.state ), {}, id: "state"%>
<%= form.select :city, options_for_select([["Select a City",""]]),{}, :id => 'city' %>
</fieldset>
<div class="actions">
<%= form.submit %>
</div>
</form>
</div>
<% end %>
<script type="text/javascript">
var selectedCity;
<% if product.city.present? %>
selectedCity = <%= product.city %>;
<% end %>
$(function() {
if ($("select#state").val() == "") {
$("select#city option").remove();
var row = "<option value=\"" + "" + "\">" + "city" + "</option>";
$(row).appendTo("select#city");
}
var $val = $("select#state").val();
if($val != ""){
getCitiesOfState($val)
}
$("select#state").change(function() {
var id_value_string = $(this).val();
if (id_value_string == "") {
$("select#city option").remove();
var row = "<option value=\"" + "" + "\">" + "city" + "</option>";
$(row).appendTo("select#city");
} else {
// Send the request and update city dropdown
getCitiesOfState(id_value_string)
}
});
});
</script>
my Products Controller
class ProductsController < ApplicationController
before_action :authenticate_user!, except: [:index, :show]
before_action :set_product, only: [:show, :edit, :update, :destroy]
# GET /products
# GET /products.json
def index
@products = Product.all
end
# GET /products/1
# GET /products/1.json
def show
end
# GET /products/new
def new
@product = current_user.shop.products.build
end
# GET /products/1/edit
def edit
end
# POST /products
# POST /products.json
def create
@product = current_user.shop.products.build(product_params)
@product.user = current_user
respond_to do |format|
if @product.save
format.html { redirect_to @product, notice: 'Product was successfully created.' }
format.json { render :show, status: :created, location: @product }
else
format.html { render :new }
format.json { render json: @product.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /products/1
# PATCH/PUT /products/1.json
def update
respond_to do |format|
if @product.update(product_params)
format.html { redirect_to @product, notice: 'Product was successfully updated.' }
format.json { render :show, status: :ok, location: @product }
else
format.html { render :edit }
format.json { render json: @product.errors, status: :unprocessable_entity }
end
end
end
# DELETE /products/1
# DELETE /products/1.json
def destroy
@product.destroy
respond_to do |format|
format.html { redirect_to products_url, notice: 'Product was successfully destroyed.' }
format.json { head :no_content }
end
end
#new methods
def get_cities_by_state
@cities = State.find(params[:state]).cities
respond_to do |format|
format.json { render :json => @cities }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_product
@product = Product.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def product_params
params.require(:product).permit(:name, :price, :description, :image, :imagetwo, :imagethree, :category, :city, :state, :sub_category)
end
end
My home page
<% if mobile_device == "mobile" %>
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
<meta name="author" content="Colorlib">
<meta name="description" content="#">
<meta name="keywords" content="#">
<!-- Page Title -->
<title>Listing & Directory Website Template</title>
<!-- Bootstrap CSS -->
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400i,500,700,900" rel="stylesheet">
<!-- Simple line Icon -->
<link rel="stylesheet" href="/assets/simple-line-icons.css">
<!-- Themify Icon -->
<link rel="stylesheet" href="/assets/themify-icons.css">
<!-- Hover Effects -->
<link rel="stylesheet" href="/assets/set1.css">
<!-- Main CSS -->
<link rel="stylesheet" href="/assets/style.css">
</head>
<body>
<%= render 'welcome/sub' %>
<section class="slider d-flex align-items-center" style="max-height:80px;">
<!-- <img src="/assets/slider.jpg" class="img-fluid" alt="#"> -->
<div class="container" >
<div class="row d-flex justify-content-center">
<div class="col-md-12">
<div class="slider-title_box">
<div class="row">
<div class="col-md-12">
<div class="slider-content_wrap">
<br>
<br>
</div>
</div>
</div>
<div class="row d-flex justify-content-center">
<div class="col-md-10">
<form class="form-wrap mt-4">
<div class="btn-group" role="group" aria-label="Basic example">
<input type="text" placeholder="What are your looking for?" id="search" class="btn-group1">
<%= select_tag :state, options_for_select([["Select a state",""]] + State.all.map { |c| [c.name, c.id] } ), id: "state"%>
<%= select_tag :city, options_for_select([["Select a City",""]]), :id => 'city' %>
<a href="/welcome/search" class="btn-form search-btn">SEARCH<i class="pe-7s-angle-right"></i></a>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<div class="col-md-5">
<div class="styled-heading">
<h3>What are you finding?</h3>
</div>
</div>
</div>
</body>
</html>
<script>
function openNav() {
document.getElementById("mySidenav").style.width = "250px";
}
function closeNav() {
document.getElementById("mySidenav").style.width = "0";
}
</script>
<script>
$(window).scroll(function() {
// 100 = The point you would like to fade the nav in.
if ($(window).scrollTop() > 100) {
$('.fixed').addClass('is-sticky');
} else {
$('.fixed').removeClass('is-sticky');
};
});
</script>
</body>
</html>
<% else %>
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="author" content="Colorlib">
<meta name="description" content="#">
<meta name="keywords" content="#">
<!-- Page Title -->
<title>Listing & Directory Website Template</title>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="/assets/bootstrap.min.css">
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400i,500,700,900" rel="stylesheet">
<!-- Simple line Icon -->
<link rel="stylesheet" href="/assets/simple-line-icons.css">
<!-- Themify Icon -->
<link rel="stylesheet" href="/assets/themify-icons.css">
<!-- Hover Effects -->
<link rel="stylesheet" href="/assets/set1.css">
<!-- Main CSS -->
<link rel="stylesheet" href="/assets/style.css">
</head>
<section class="slider d-flex align-items-center">
<!-- <img src="/assets/slider.jpg" class="img-fluid" alt="#"> -->
<div class="container">
<div class="row d-flex justify-content-center">
<div class="col-md-12">
<div class="slider-title_box">
<div class="row">
<div class="col-md-12">
<div class="slider-content_wrap">
<br>
<br>
<br>
<br>
<h1>Discover what's great Near You</h1>
<h5>Let's uncover the best places to eat, drink, and shop nearest to you.</h5>
</div>
</div>
</div>
<div class="row d-flex justify-content-center">
<div class="col-md-10">
<form class="form-wrap mt-4">
<div class="btn-group" role="group" aria-label="Basic example">
<input type="text" placeholder="What are your looking for?" id="search" class="btn-group1">
<%= select_tag :state, options_for_select([["Select a state",""]] + State.all.map { |c| [c.name, c.id] } ), id: "state"%>
<%= select_tag :city, options_for_select([["Select a City",""]]), :id => 'city' %>
<a href="/welcome/search" class="btn-form search-btn">SEARCH<i class="pe-7s-angle-right"></i></a>
</div>
</form>
<div class="slider-link">
<a href="/welcome/popular">Browse Popular</a><span>or</span> <a href="/welcome/recent">Recently Addred</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<script>
function openNav() {
document.getElementById("mySidenav").style.width = "250px";
}
function closeNav() {
document.getElementById("mySidenav").style.width = "0";
}
</script>
</body>
<% end %>
</script>
<script>
$(window).scroll(function() {
// 100 = The point you would like to fade the nav in.
if ($(window).scrollTop() > 100) {
$('.fixed').addClass('is-sticky');
} else {
$('.fixed').removeClass('is-sticky');
};
});
var selectedCity;
$("select#state").change(function() {
var id_value_string = $(this).val();
if (id_value_string == "") {
$("select#city option").remove();
var row = "<option value=\"" + "" + "\">" + "city" + "</option>";
$(row).appendTo("select#city");
} else {
// Send the request and update city dropdown
getCitiesOfState(id_value_string)
}
});
$(".search-btn").on("click", function(e){
e.preventDefault()
var $this = $(this);
var $href = $this.attr("href");
var state = $("#state").val()
var city = $("#city").val()
var search = $("#search").val()
window.location = $href + '?search=' + search+ "&state=" +state+ "&city="+ city
})
function getCitiesOfState(val){
$.ajax({
dataType: "json",
cache: false,
beforeSend: function(xhr) {xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))},
url: '/get_cities_by_state',
type: 'post',
data: {"state" : val},
timeout: 5000,
error: function(XMLHttpRequest, errorTextStatus, error) {
alert("Failed to submit : " + errorTextStatus + " ;" + error);
},
success: function(data) {
// Clear all options from city select
$("select#city option").remove();
//put in a empty default line
// Fill city select
var row = "<option value=\"" + "" + "\">" + "Select a city" + "</option>";
$(row).appendTo("select#city");
$.each(data, function(i, j) {
if(j.id == selectedCity){
row = "<option value=\"" + j.id + "\" selected>" + j.name + "</option>";
}else{
row = "<option value=\"" + j.id + "\">" + j.name + "</option>";
}
$(row).appendTo("select#city");
});
}
});
}
</script>
</html>
My search
def search
@products = Product.where('(name LIKE ? OR description LIKE ? )', "%#{params[:search]}%", "%#{params[:search]}%")
@products = @products.where(state: params[:state]) if params[:state].present?
@products = @products.where(city: params[:city]) if params[:city].present?
end
*Routes*
post :get_cities_by_state, action: :get_cities_by_state, controller: :products