is there a way to convert an array in Ruby to a float by removing the brackets? - ruby-on-rails

I have a little problem that seems rather easy to solve but I can't seem to find a solution. I'm using the Geocoder gem for Rails and from this method of:
Geocoder.coordinates(params[:search])
I'm getting an array that contains floats like this: [43.653226, -79.3831843]
My question is, is there a way to remove the brackets from the array or convert the value to a float so the output is 43.653226, -79.3831843?
My closest solution so far has been to do this:
a = Geocoder.coordinates(params[:search])
and then to obtain each float individually by doing this in the method call:
a[0] --> 43.653226
a[-1] --> -79.3831843
This doesn't seem to work as I get an error with the particular method that I am trying to use.
I'm using the 'sunspot-solr' and 'sunspot-rails' gem for this and what I am trying to do is allow a user to enter a city to find users and then display users near that city within a 100, 200 km radius
This is what I have in my user.rb file:
class User < ActiveRecord::Base
searchable do
text :city
latlon(:location) { Sunspot::Util::Coordinates.new(latitude, longitude) }
end
end
This is what's in my users_controller.rb
def index
if params[:search]
#search = User.search do
fulltext params[:search]
with(:location).near(*Geocoder.coordinates(params[:search]),:precision => 6)
end
#users = #search.results
end
end
This is the line that seems to be causing the problem: with(:location).near(*Geocoder.coordinates(params[:search]),:precision => 6)
And finally in my view, this is the search form:
<%= form_tag users_path, class: "form-signin", role: "form", method: :get do %>
<%= text_field_tag :search, params[:search], class: "form-control", placeholder:"Type in a location" %>
<div><%= submit_tag "Search users", class: "btn btn-lg btn-primary btn-block", id: "home-search" %></div>
<% end %>
Now when I'm trying to add the geospatial feature I'm getting a 400 error that looks like this:
RSolr::Error::Http - 400 Bad Request Error: {'responseHeader'=>{'status'=>400,'QTime'=>2},'error'=>{'msg'=>'com.spatial4j.core.exception.InvalidShapeException: incompatible dimension (2) and values (dpz83dffmxps). Only 0 values specified','code'=>400}}
If anyone can help that'd me great!

The values are floats already, if you want to use the content of the array as 2 arguments to a method call then you can use the splat operator (*) e.g
method_call(*[43.653226, -79.3831843]) is same as method_call(43.653226, -79.3831843)
or destructure the array and pass the new variables as argument e.g:
lat, lng = [43.653226, -79.3831843]
method_call(lat,lng)

You could use join:
eg.
a = Geocoder.coordinates(params[:search])
a.join(", ");
Would return the array - comma separated.

Related

Search through .select().group().distinct possible?

I want to create a search select that works on unique names through grouping...
The goal is to find duplicates to then use as a search parameter.
I want to find LineItem's :store_title's that match so I can create a select drop down for a way to search through LineItem's that match the specific :store_title.
Example:
LineItem DB:
line_item.title = "Hello"
line_item.title = "Hello"
line_item.title = "Okay"
line_item.title = "Bar"
I want to have a drop down select_tag in a search for the following:
[select]
"Hello"
"Okay"
"Bar"
And append all results that match LineItem.title of those which is selected.
I tried a few ways:
I so far have been able to get the unique drop down select field to "work" but not sure if it is the right way because it creates an array:
Controller:
#vendor_line_items = LineItem.where(vendor_id: #vendor.id).select(:store_title).group(:store_title).distinct
if params[:search]
#orders = Order.line_item_search(params[:search]).joins(:line_items).where(line_items: {vendor_id: #vendor.id})
end
ORders Model:
def self.line_item_search(search)
scope = joins(:line_items)
line_items = scope.where(line_items: { id: LineItem.where(store_title: "#{search.downcase}") })
line_items
end
View:
<%= form_tag vendor_orders_path, :method => 'get' do %>
<%= collection_select(:search, params[:search], #vendor_line_items, :store_title, :store_title, {}, {class: "form-control-sm col-5"})%>
<%= submit_tag "Search", :name => nil, class: "btn btn-primary btn-sm" %>
<% end %>
Error:
Undefined method 'downcase' for ["store_title"]:Array:
Can I alter my model to allow the array, or should i be finding the unique store titles another way?
If you just want to downcase the strings in that array, you could do something like this:
line_items = scope.where(line_items: { id: LineItem.where(store_title: search.map(&:downcase)) })
That will provide a list of downcased strings to your query.
I tried finding a way to remove the brackets before searching so the brackets were not present in the search parameters but couldn't figure it out.
Doing...:
line_items = scope.where(line_items: { id: LineItem.where(store_title: "#{search.join(', ')}") })
Solved it. This removes the brackets before searching the DB and works.
**
UPDATE:
**
View for response and answer to my issue:
Rails search form through arrays doesn't work on second search attempt

How to query the activerecord based on the enum status?

I am trying implement a search/filter action on a model Production based on a column status. The column status is of integer type. Later for the purpose of readability I used enum datatype on status column as follows.
class Production < ApplicationRecord
enum status:{
Preproduction:1,
Postproduction: 2,
Completed:3
}
end
Then I started to work on a search/filter functionality to fetch the record based on the status given by the user.
productions_controller
def filter
if params[:filter]
#productions = Production.where('productions.status like ?', "%#{params[:filter]}%")
else
#productions = Production.all
end
end
view
<%= form_tag [:filter, :productions], :method => 'get' do %>
<p>
<%= text_field_tag :filter, params[:filter] %>
<%= submit_tag "Filter", :status => nil %>
</p>
<% end %>
Now I am able to query the record properly only if I enter the integer values like 1 2 or 3 in the text field. When I enter the status like Preproduction like I assigned, I am not getting the result. I am getting a blank page. How can I fix this ? How can I make it to accept the string and query successfully ?
You can do this...
#productions = Production.where('productions.status like ?', "%#{Production.statuses[params[:filter]]}%")
Enums have a pluralized class method, so enum status in Production has a hash
Production.statuses which looks like your status hash but with the symbols changed into strings.

Searching for parameter value in a postgres column

I'm attempting to implement an advanced search on my Rails 5 site. The user passes in a parameter "provider_type", and I would like to return all records that contain that value. The value is chosen from a dropdown list using simple-form. My new.html.erb looks like this:
<%= simple_form_for Search.new, :html => {:class => 'form-horizontal' } do |f| %>
<%= f.input :provider_type, collection: ['Mental Health', 'Medical'] %>
<%= f.button :submit %>
<% end %>
My Search model looks like this:
class Search < ApplicationRecord
def search_providers
providers = Provider.all
providers = providers.where("provider_type LIKE ?", ['Mental Health', 'Medical']) if provider_type.present?
providers
end
end
And my Searches controller:
def SearchesController < ApplicationController
def new
#types = Provider.uniq.pluck(:provider_type)
end
private
def search_params
params.require(:search).permit(:provider_type)
end
end
end
When I try to search for 'Mental Health' in the search form, I get this error: PG::UndefinedFunction: ERROR: operator does not exist: character varying[] ~~ unknown
EDIT
When I reword it as
providers.where(provider_type: provider_type) if provider_type.present?
This produces the error "PG::InvalidTextRepresentation: ERROR: malformed array literal: "%Mental Health%" DETAIL: Array value mut start with "{" or dimension information.
Probably you need not LIKE operator but IN. IN (or ANY) checks if fields match to one of element of array:
providers.where(provider_type: provider_type) if provider_type.present?
Rails 3 / Ruby: ActiveRecord Find method IN condition Array to Parameters single quote issue

DRY and Elegant way to represent all search combinations without growing exponentially?

Right now I can search the following
1) leaving_from location
2) going_to location
3) leaving_from &
going_to location
if params[:leaving_from].present? && params[:going_to].present?
#flights = Flight.where(:source => params[:leaving_from]).where(:destination => params[:going_to])
elsif params[:leaving_from].present?
#flights = Flight.where(:source => params[:leaving_from])
elsif params[:going_to].present?
#flights = Flight.where(:destination => params[:going_to])
end
Is there a dry way to represent this code above? Basically its a for search function compromised of 2 drop down search boxes. One for leaving from location and another for going to location. With the option of narrowing it down by both locations or just one location.
It works fine now but it isn't very scalable. If I added more search parameters say price and time, it would grow exponentially in order to be able to represent all the states.
For example if I added price my new combinations would be
1) leaving_from location
2) going_to location
3) leaving_from &
going_to location
4) price
5) leaving_from location & price
6) going_to location & price
7) leaving_from location & going_to location & price
I need help to figure out a better way to represent this, or else it would make my controller incredibly bloated.
EDIT FORM CODE --
=form_tag '/flights', :method => :get
%h4
Leaving From:
=select_tag 'leaving_from', content_tag(:option,'select one...',:value=>"")+options_for_select(#flights_source, 'source'), { :class => 'form-control' }
%h4
Going To:
=select_tag 'going_to', content_tag(:option,'select one...',:value=>"")+options_for_select(#flights_destination, 'destination'), { :class => 'form-control' }
%h4=submit_tag "Search", :name => nil, :class => 'btn btn-success btn-md btn-block'
In place of using leaving_from or going_to use source and destination instead and Move all the required parameters under a key, e.g., this solution will work for any no. of keys
'required' => { 'source' => value, 'destination' => value, 'price' => value }
Now in the controller define this method in private
def get_flights(params)
possible_combination = []
conditions = {}
key_array = params['required'].keys
1.upto(key_array.length) { |i| possible_combination + key_array.combination(i).to_a }
possible_combination.reverse.each do |comb|
if comb.collect{ |key| params['required'][key].present? }.inject(:&)
comb.map { |key| conditions[key] = params['required'][key] }
break
end
end
Flight.where(conditions)
end
Call this method from any action
#flights = get_flights(params)
Hope this works! Its an overall idea to make this thing dynamic, you can refactor the code according to your need!
First things first: your code does not do what you think it does, since there is no way for it to execute the third if (every time the third if is true, the first if is as well). On to your question:
#flights = Flight
#flights = #flights.where(:source => params[:leaving_from]) if params[:leaving_from].present?
#flights = #flights.where(:destination => params[:going_to]) if params[:going_to].present?
Or
conditions = {}
conditions[:source] = params[:leaving_from] if params[:leaving_from].present?
conditions[:destination] = params[:going_to] if params[:going_to].present?
#flights = Flight.where(conditions)
How about using ransack which adds your rails to search function very easily.
You just write below, if you use ransack.
# View (Search Form)
<%= search_form_for #q do |f| %>
From: <%= f.text_field :leaving_from_cont %>
To : <%= f.text_field :going_to_cont %>
Price:
<%= f.text_field :price_gteq %> 〜 <%= f.text_field :price_lteq %>
<%= f.submit %>
<% end %>
# Controller
def index
#q = Flight.ransack(parmas[:q])
#flights = #q.result(distinct: true)
end
If a user don't input any fields, ransack don't use the non-input fields value. It means don't add WHERE conditions in DB.
column_name_cont means contain (Like in DB).
column_name_eq means equal (== in DB).
column_name_gteq means greater than equal (<= in DB).
column_name_lteq means less than equal (>= in DB).
etc...
Also you can sort the search result easily by using sort_link methods of ransack.
Please look in ransack.
I was not able to get #RSB's code to work but I was able to use his example to create a method that did work. I call the below code in my action.
#flights = get_flights(search_params)
The search_params method is as follows:
def search_params
params.permit(:leaving_from, :going_to)
params_hash = {'required' => { 'source' => params[:leaving_from], 'destination' => params[:going_to]}}
end
And finally the get_flights method is:
def get_flights(params)
possible_combination = []
conditions = {}
key_array = params['required'].keys
possible_combination = (possible_combination + key_array.combination(key_array.length).to_a).flatten
possible_combination.each do |comb|
conditions[comb] = params['required'][comb] if params['required'][comb].present?
end
Flight.where(conditions)
end
I am still pretty new to ruby and rails so any feedback or suggestions for improvements would be greatly welcome. Thanks!

How to display Rails select field values rather than stored integers in other views

I'm using a select field in a Rails app that is NOT tied to a related model, but stores integer values for a static series of options , i.e.,
<%= select (:this_model, :this_field, [['Option1',1],['Option2',2],['Option3',3],['Option4',4]] ) %>
In a show/ index view, if I want to display the option text (i.e. Option1, Option2, etc) rather than the integer value stored in the database, how do I achieve this?
Thanks for helping a noob learn the ropes!
EDIT
Based on Thorsten's suggestion below, I implemented the following. But it is returning nil, and I can't figure out why.
Invoice model:
##payment_status_data = { 1 => "Pending Invoice" , 2 => "Invoiced" , 3 => "Deposit Received", 4 => "Paid in Full"}
def text_for_payment_status
##payment_status_data[payment_status]
end
Invoice show view:
Payment Status: <%= #invoice.text_for_payment_status %>
In the console:
irb > i=Invoice.find(4)
=> [#<Invoice id: 4, payment_status: 1 >]
irb > i.text_for_payment_status
=> nil
I've tried defining the hash with and without quotes around the keys. What am I missing?
something like this would work:
<%= form_for #my_model_object do |form| %>
<%= form.label :column_name "Some Description" %>
<%= form.select :field_that_stores_id, options_for_select({"text1" => "key1", "text 2" => "key2"}) %>
<% end %>
Update
If you later want to display the text you can get it from a simple hash like this:
{"key1" => "text 1", "key2" => "text2"}[#my_object.field_that_stores_id]
But you better store this hash somewhere in a central place like the model.
class MyModel < ActiveRecord
##my_select_something_data = {"key1" => "text 1", "key2" => "text2"}
def text_for_something_selectable
##my_select_something_data[field_that_stores_id]
end
end
Then you can use it in your views like
#my_object.text_for_something_selectable
There are many possible variations of this. But this should work and you would have all information in a central place.
Update
Ok, I used something similar for our website. We need to store return_headers for rma. Those need to store a return reason as a code. Those codes are defined in an external MS SQL Server Database (with which the website exchanges lots of data, like orders, products, and much more). In the external db table are much more return reasons stored than I actually need, so I just took out a few of them. Still must make sure, the codes are correct.
So here goes he model:
class ReturnHeader < AciveRecord::Base
##return_reason_keys = {"010" => "Wrong Produc",
"DAM" => "Damaged",
"AMT" => "Wrong Amount"}
def self.return_reason_select
##return_reason_keys.invert
end
def return_reason
##return_reason_keys[nav_return_reason_code]
end
end
Model contains more code of course, but that's the part that matters. Relevant here is, that keys in the hash are strings, not symbols.
In the views i use it like this:
In the form for edit:
<%= form_for #return_header do |form| %>
<%= form.label :nav_return_reason_code "Return Reason" %>
<%= form.select :nav_return_reason_code, options_for_select(ReturnHeader.return_reason_select, #return_header.nav_return_reason_code) %>
<% end %>
(Maybe no the most elegant way to do it, but works. Don't know, why options_for_select expects a hash to be "text" => "key", but that's the reason, why above class level method returns the hash inverted.)
In my index action the return reason is listed in one of the columns. There I can get the value simply by
#return_headers.each do |rh|
rh.return_reason
end
If you have trouble to get it run, check that keys a correct type and value. Maybe add some debug info with logger.info in the methods to see what actual data is used there.

Resources