Rails : can't convert Regexp into Integer - ruby-on-rails

I have the following code in my rails controller:
#main_mastertest = $connection.execute("SELECT * FROM builds;")
#l2_tmp_mastertest = Array.new
#l2_tmp_mastertest = #main_mastertest.map {|y|[y[0]]}
#l2_mastertest = Array.new
#l2_mastertest = #l2_tmp_mastertest.inject(Hash.new(0)) { |hash,element|
hash[element] +=1
hash }
#l2_mastertest = #l2_mastertest.sort_by { |x, _| x }.reverse
After that I try to do something like this in my view :
<% #l2_mastertest.each_with_index do |row1, index1| %>
<% #l2_mastertest.each_with_index do |row2, index2| %>
<% if row2[0][ /(\d+\.\d+)/ ].to_s == row1[0].to_s %> # LINE X
..................
<% end %>
<% end %>
<% end %>
But it gives me an error on line X saying : can't convert Regexp into Integer

If I simulate what I think is going on with the data structures in your question, I get this:
#l2_mastertest = { '3.1.4' => 7, '1.2.3' => 8 }
=> {"3.1.4"=>7, "1.2.3"=>8}
#l2_mastertest.each_with_index { |row2,index| p row2,index }
["3.1.4", 7]
0
["1.2.3", 8]
1
So a structure like row2[0][ /(\d+\.\d+)/ ] is the same as e.g. "3.1.4"[ /(\d+\.\d+)/ ]
Edit: Removed my previous "answer", because actually "3.1.4"[ /(\d+\.\d+)/ ] => "3.1", which is fine in Ruby (and I learned something today :-). Something else (possibly in code not shown) is making the #l2_mastertest hash not behave as expected.
Potentially this is a database/model issue, and as commenters have suggested, row[0] does not contain a string.
I would suggest instead that SELECT * FROM builds; is risky, since you are relying on database to return columns in particular order. You should change it to fetch the column data you need, in order e.g.
SELECT version, result, build_id FROM builds;
so that you are certain that later processing is working with the column that you think it is. Simply re-building or transferring the database could change the order that the RDBMS returns the columns in a SELECT * and make previously-working code break.

Related

Rails: Chartkick cummulative user graph

I'm using chartkick in an active admin dashboard and trying to track a cumulative user base over time.
Using groupdate to count by week I can successfully create a chart displaying point in time counts but struggling to display cumulative results.
Any suggestion on best way to approach as I have not found a similar question?
chart partial
<%= javascript_include_tag "https://www.gstatic.com/charts/loader.js" %>
<%= line_chart User.group_by_week(:created_at).count %>
dashboard.rb
column do
panel "Recent User Additions" do
table_for User.order("id desc").limit(10).each do |_user|
column(:email) { |user| link_to(user.email, admin_user_path(user)) }
column(:state_waters) { |user| link_to(user.state_waters, admin_user_path(user)) }
column(:state_waters) { |user| link_to(user.home_port, admin_user_path(user)) }
end
end
If I understand your question, you need to manipulate the hash of data.
In controller do somehing like this:
#data = User.group_by_week(:created_at).count
accumulator = 0
#data.transform_values! do |val|
val += accumulator
accumulator = val
end
Then show the chart in view as <%= line_chart #data %>
If you inspect the hash <%= User.group_by_week(:created_at).count.inspect %> it becomes clear.
In order to use accumulator over any hash, could be useful to add a custom method to Class hash.
module HashPatch
def accumulate_values!
accumulator = 0
transform_values! do |val|
val+= accumulator
accumulator = val
end
end
end
Hash.include HashPatch
points = {'x1' => 0, 'x2' => 10, 'x3' => 10, 'x4' => 10.1}
points.accumulate_values! #=> {"x1"=>0, "x2"=>10, "x3"=>20, "x4"=>30.1}
transform_values! since Ruby v4.2.1

Displaying XML Hashes in Rails Views Not Working

I have narrowed down a 33,364 entry XML file to the 1,068 that I need. Now I am attempting to gather pieces of information from each node that I have narrowed my search down to, and store each piece of information in a hash, so that I can list out the relevant data in a rails view.
Here is the code in my controller (home_controller.rb) --
class HomeController < ApplicationController
# REQUIRE LIBRARIES
require 'nokogiri'
require 'open-uri'
def search
end
def listing
#properties = {}
# OPEN THE XML FILE
mits_feed = File.open("app/assets/xml/mits.xml")
# OUTPUT THE XML DOCUMENT
doc = Nokogiri::XML(mits_feed)
doc.xpath("//Property/PropertyID/Identification[#OrganizationName='northsteppe']").each do |property|
# GATHER PROPERTY INFORMATION
information = {
"street_address" => property.xpath("Address/AddressLine1").text,
"city" => property.xpath("Address/City").text,
"zipcode" => property.xpath("Address/PostalCode").text,
"short_description" => property.xpath("Information/ShortDescription").text,
"long_description" => property.xpath("Information/LongDescription").text,
"rent" => property.xpath("Information/Rents/StandardRent").text,
"application_fee" => property.xpath("Fee/ApplicationFee").text,
"bedrooms" => property.xpath("Floorplan/Room[#RoomType='Bedroom']/Count").text,
"bathrooms" => property.xpath("Floorplan/Room[#RoomType='Bathroom']/Count").text,
"bathrooms" => property.xpath("ILS_Unit/Availability/VacancyClass").text
}
# MERGE NEW PROPERTY INFORMATION TO THE EXISTING HASH
#properties.merge(information)
end
end
end
I'm not getting any errors and my view is loading fine, but it is pulling up blank. Here is my view file (listing.html.erb) --
<div class="propertiesHolder">
<% if #properties %>
<ul>
<% #properties.each do |property| %>
<li><%= property.information.street_address %></li>
<% end %>
</ul>
<% else %>
<h1>There are no properties that match your search</h1>
<% end %>
</div>
Does anyone know why this might be pulling up blank? I would assume that I would receive an error if I had done something incorrect in the code. I also tried just outputting "Hello World" as text for each |property| and this also pulled up blank. Thank you!
Ruby merge does not mutate your hash. It just returns the two hashes as one.
Example
h1 = { "a" => 100, "b" => 200 }
h2 = { "b" => 254, "c" => 300 }
h1.merge(h2)
#=> {"a"=>100, "b"=>254, "c"=>300}
h1
#=> {"a"=>100, "b"=>200}
Note how h1 still retains its original values?
What you will want to do is rename your information hash to #properties. I suggest this because you are merging a hash with information in it (information) with an empty hash (#properties). So instead of overwriting when you merge the hashes, just use the first hash.

Rails issue with params hash

I need to export a previously rendered table from my view to pdf. When I build the array of hashes as follows:
__index = 0
#people.each do |p| %>
#pdfdata[__index] = {
[:name] => p.name.to_s,
[:surname] => p.surname.to_s
__index += 1
end
end
and send it to the controller in order to export it on a pdf as follows:
hidden_field_tag(:pdfdata, #pdfdata)
when I get the params[:pdfdata] I cannot find a way unless I build a string parser to map the data accordingly... is there a better way to do this?
Modifying your code a little bit to get
#people.each_with_index do |p,i| %>
#pdfdata[i] = {
[:name] => p.name.to_s,
[:surname] => p.surname.to_s}
end
and use this gem to create the hidden has field
https://github.com/brianhempel/hash_to_hidden_fields

Ruby - bad output from arrays

I have a form with a lots of these text inputs:
<%= text_field_tag 'name[seq]['+dat.id.to_s+']', dat.seq%>
After send this form I want to save them to database, I try to get the values from inputs in each loop:
unless params[:name].nil?
params[:name][:seq].each_with_index do |sq, i|
puts sq
end
end
But the output in terminal is wrong, for example if I have an input with the values
<%= text_field_tag 'name[seq][25]', 3%>
So I am going to expect the output is 3, but I will get to terminal this:
25
3
Is here something important, what I don't see?
Yes, you are missing something. Within your each_with_index block, sq will be an array and that's why you get that output.
So, what's going on here? Well, your params will contain this:
"name" => { "seq" => { "25" => "3" } }
And that means that params[:name][:seq] is this:
{ "25" => "3" }
Then you apply each_with_index to that to iterate through the Hash. If you do it like this:
params[:name][:seq].each_with_index do |(k,v), i|
puts "-#{k}-#{v}-"
end
you'll see what's going on.
If you just want the 3 then you can iterate over params[:name][:seq] as above and just look at v inside the block or, if you know what the '25' is some other way, you could just go straight there:
three = params[:name][:seq]['25']

Passing hash as values in hidden_field_tag

I am trying to pass some filters in my params through a form like so:
hidden_field_tag "filters", params[:filters]
For some reason the params get changed in the next page. For example, if params[:filters] used to be...
"filters"=>{"name_like_any"=>["apple"]} [1]
...it gets changed to...
"filters"=>"{\"name_like_any\"=>[\"apple\"]}" [2]
note the extra quotations and backslashes in [2] when compared to [1].
Any ideas? I'm attempting to use this with searchlogic for some filtering, but I need it to persist when I change change objects in forms. I would prefer not to have to store it in session.
My solution was just to re-create each of param with key-value pair:
<% params[:filters].each do |key,value| %>
<%= hidden_field_tag "filters[#{key}]",value %>
<% end %>
You actually want/need to 'serialize' a hash using hidden fields.
Add this to your ApplicationHelper :
def flatten_hash(hash = params, ancestor_names = [])
flat_hash = {}
hash.each do |k, v|
names = Array.new(ancestor_names)
names << k
if v.is_a?(Hash)
flat_hash.merge!(flatten_hash(v, names))
else
key = flat_hash_key(names)
key += "[]" if v.is_a?(Array)
flat_hash[key] = v
end
end
flat_hash
end
def flat_hash_key(names)
names = Array.new(names)
name = names.shift.to_s.dup
names.each do |n|
name << "[#{n}]"
end
name
end
def hash_as_hidden_fields(hash = params)
hidden_fields = []
flatten_hash(hash).each do |name, value|
value = [value] if !value.is_a?(Array)
value.each do |v|
hidden_fields << hidden_field_tag(name, v.to_s, :id => nil)
end
end
hidden_fields.join("\n")
end
Then, in view:
<%= hash_as_hidden_fields(:filter => params[:filter]) %>
This should do the trick, even if you have a multilevel hash/array in your filters.
Solution taken http://marklunds.com/articles/one/314
I just wrote a gem to do this called HashToHiddenFields.
The core of the gem is this code:
def hash_to_hidden_fields(hash)
query_string = Rack::Utils.build_nested_query(hash)
pairs = query_string.split(Rack::Utils::DEFAULT_SEP)
tags = pairs.map do |pair|
key, value = pair.split('=', 2).map { |str| Rack::Utils.unescape(str) }
hidden_field_tag(key, value)
end
tags.join("\n").html_safe
end
Here's how I managed to pass a parameter value through my view - that is, from View A through View B and on to the controller:
In View A (index):
<%= link_to 'LinkName', {:action => "run_script", :id => object.id} %>
In View B (run_script):
<%= form_tag :action => 'index', :id => #object %>
<%= hidden_field_tag(:param_name, params[:id]) %>
In the controller:
Just reference params[:param_name] to make use of the value.
The key transition that wasn't documented anywhere I could find is where {... :id => object.id} from View A is passed on to View B as <%... :id => #object %>, which View B then passes on to the controller as (:param_name, params[:id]) through the hidden_field_tag construct.
I didn't see this documented anywhere but after perusing several posts across several sites including this post (whose syntax provided the key inspiration), the solution finally gelled. I've seen the caveats on hidden fields pertaining to security but have found no other way to do this given my current design, such as it is.
it's because when you convert in HTML with your hidden_field_tag, the backquote is add. After when you received it like a string not a Hash.
The Hash type can't exist in HTML. You have only string. So if you want pass your hash (not recommend by me), you need eval it when you received it. But can be a big security issue on your application.
As a caveat to Vlad's answer, I had to use raw:
<%= raw hash_as_hidden_fields(:filter => params[:filter]) %>
to get it to work in Rails 3.1.1. Essentially, the text being output was being escaped, eg., "<" becoming "&lt".
Assuming the hash is strings, symbols, numbers, and arrays, you can call eval to convert the params string of the hash from the hidden_fields form back into a hash in the controller. Then the backslash escape characters for the quotes added are no longer an issue:
hash = eval(params["hash_string"].to_s)
Credit to the following article for helping identify this simple solution for my case:
How do I convert a String object into a Hash object?
Keep in mind the contents of the params should be cleaned with .require and .permit.

Resources