I have a ruby script called abc.rb in rails config/initializers
require 'http'
class Abc
def initialize(url)
#url = url
#doc = web_lookup(#url)
end
def web_lookup(url_to_open)
begin
return Nokogiri::HTML(HTTP.get(url_to_open).to_s)
rescue
"Please check your URL!"
end
end
def frequency_count
#word_array = #doc.css("p").text.split(" ")
#occurance = Hash.new(0)
#word_array.each {|x| #occurance[x.downcase] += 1 }
#occurance.each {|x,y|
if y > 5
puts "#{x} : #{y} times"
end
}
end
end
And I'm trying to access that script's class in a rails controller.
class UrlsController < ApplicationController
def index
#url_to_check = Abc.new("http://ecodehut.com/linux")
end
end
Everything is fine so far but when I call this variable in index.html.erb <%= #url_to_check.frequency_count %> output is this:
{"it’s"=>1, "like"=>1, "asking"=>1, "“should"=>1, "i"=>5, "go"=>3, "to"=>14, "school?”"=>1, "and"=>8, "“would"=>1, "get"=>1, "a"=>3, "job"=>1, "if"=>2, "school?”.list"=>1, "of"=>1, "advantages"=>1, "is"=>5, "never"=>1, "ending"=>1, "elaborating"=>1, "each"=>1, "throw"=>1, "your"=>2, "mouse"=>1, "away"=>1, "this"=>3, "time."=>1, "keyboard"=>1, "all"=>1, "need"=>1, "mozart."=>1, "navigate..."=>1, "before"=>2, "we"=>1, "begin"=>1, "with"=>3, "configuration"=>1, "here"=>1, "download"=>1, "install"=>2, "system."=>1, "after"=>1, "come"=>1, "back"=>1, "continue."=>1}
But my expected output is this:
to : 14 times
and : 8 times
you : 9 times
the : 6 times
I'm not getting why rails printing everything inside the hash instead of the key values with values bigger than 5 like mentioned in the frequency_count method.
P.S: Abc.rb script results fine and dandy when ran in terminal using ruby Abc.rb
Plese change this and try again
def frequency_count
#word_array = #doc.css("p").text.split(" ")
#occurance = Hash.new(0)
#word_array.each {|x| #occurance[x.downcase] += 1 }
#occurance.select {|x, y| y> 5}
end
The reason is the last line of your method is
#occurance.each {|x,y|
if y > 5
puts "#{x} : #{y} times"
end
}
Just iterate all key and values inside #occurance variable but not sort based on the count. So you are getting all key values in the views instead which has count more than 5.
When you do #occurance.select {|x, y| y> 5}, which filter your hash and gives you the desired values which count is more than 5. Now you can just loop it and print inside views.
Hope you understand.
Update
In your index.html.erb put this code, where you would like to print hash details
<% #occurance.each do |key, value| %>
<span><%= "#{key}: #{value}" %></span><br />
<% end %>
Related
Ruby newbie here working on loops with classes. I was supposed create a method that would take a string and add exclamation points to the end of each word (by making it an array with .split) and join the 'exclaimed' words as a string again. I've been at this for two hours already and decided I should seek help. I have a handful of ideas but I keep coming up with a NoMethod error. Below is one of ways that made sense to me but of course, it doesn't work. I've also added specs at the very end.
class StringModifier
attr_accessor :string
def initialize(string)
#string = string
end
def proclaim
new_array = []
string.split.each do |word|
new array = "#{word}!"
new_array.join
end
new_array
end
end
SPECS
describe StringModifier do
describe "#proclaim" do
it "adds an exclamation mark after each word" do
blitzkrieg_bop = StringModifier.new("Hey ho let's go").proclaim
expect(blitzkrieg_bop).to eq("Hey! ho! let's! go!")
end
end
end
Write your method as:
def proclaim
string.split.map { |word| "#{word}!" }.join(" ")
end
Or write it as :
def proclaim
a = string.split
("%s! " * a.size % a).strip
end
Tested :
[30] pry(main)> a = "Hey ho let's go".split
=> ["Hey", "ho", "let's", "go"]
[31] pry(main)> ("%s! " * a.size % a).strip
=> "Hey! ho! let's! go!"
[32] pry(main)>
I have a instance method called entry_sum which sums a few other instance methods.
...
def game4sum
if games[3] and games[3].winning_team_id == game4_selection
then 1
else 0
end
end
def entry_sum
game1sum + game2sum + game3sum + game4sum
end
In my view I'm running
<% #entries.each do |entry| %>
...
<%= entry.entry_sum %>
My question is, is it possible to then find the max value for entry_sum if there are X amount of entries in #entries? I'm looking to identify the entry with the highest value for entry_sum. This is my first app and I have a feeling that I need to restructure/visit class vs instance methods.
You can use detect and check the max value. I've put a full example below. You should only need to adapt the last line to your program.
require 'ostruct'
#entries = [OpenStruct.new(:entry_sum => 1), OpenStruct.new(:entry_sum => 4), OpenStruct.new(:entry_sum => 5), OpenStruct.new(:entry_sum => 2)]
#entries.detect { |entry| entry.entry_sum == #entries.map(&:entry_sum).max }
Probably been working on this too long, sloppy design, or both. My issue is I have a model I wish to initialize. The object has like 52 attributes, but I'm only setting a certain ~25 depending on which object I've just scanned. When I scan an object I get the columns and match them up with a hash_map I've created.
Example Hash Map
This just matches the scanned text to their respective attribute name.
hash_map = {"Pizza."=>"pizza_pie","PastaBowl"=>"pasta_bowl","tacos"=>"hard_shell_taco","IceCream"=>"ice_cream","PopTarts"=>"pop_tart"}
What I want to do
menu = RestaurantMenu.new(pizza_pie => var1, pasta_bowl => var2, ...)
My only problem is in my code at the moment I have this...
t.rows.each do |r|
for i in 0..r.length-1
#hash_map[t.combined_columns[i]] => r.[i]
puts "#{hash_map["#{t.combined_columns[i]}"]} => #{r[i]}"
end
end
the puts line displays what I want, but unsure how to get that in my app properly.
Here is several ways to fix this:
hash_map = {"Pizza."=>"pizza_pie","PastaBowl"=>"pasta_bowl","tacos"=>"hard_shell_taco","IceCream"=>"ice_cream","PopTarts"=>"pop_tart"}
attributes.each do |attribute, element|
message.send((attribute + '=').to_sym, hash_map[element])
end
or like this:
class Example
attr_reader :Pizza, :PastaBowl #...
def initialize args
args.each do |k, v|
instance_variable_set("##{k}", v) unless v.nil?
end
end
end
for more details click here
I ended up doing the following method:
attributes = Hash[]
attributes["restaurant"] = tmp_basic_info.name
attributes["menu_item"] = tmp_basic_info.item_name
t.rows.each do |r|
for i in 0..r.length-1
attributes["other"] = t.other_information
attributes[hash_map[t.combined_columns[i]] = r[i]
end
row = ImportMenuItem.new(attributes)
row.save
end
I use foo helper function in my view:
<%= foo ["hello", "stack", "overflow"] %>
When foo is defined like this:
def foo(arr)
result = ''
arr.each do |a|
result += content_tag(:div, a)
end
result
end
The page renders:
<div>hello</div><div>stack</div><div>overflow</div>
But, if change foo's definition to be:
def foo(arr)
content_tag(:div, arr[0]) + content_tag(:div, arr[1]) + content_tag(:div, arr[2])
end
I get the expected result:
hello
stack
overflow
How would you fix foo's definition above to get the expected result ? (i.e. I don't want the characters to be escaped)
Try this:
def foo(arr)
result = ''
arr.each do |a|
result += content_tag(:div, a)
end
raw result
end
Edit.
To be clearer, you're creating a string and Rails doesn't know whether or not it's safe to display.
To be even more precise, Rails has no doubt concerning the content_tags it creates.
So you could solve your problem telling rails your initializer string is safe:
def foo(arr)
result = ''.html_safe
arr.each do |a|
result += content_tag(:div, a)
end
result
end
I have a method call in my view like this
<%= Navigation.with(params) do |menu|
if current_user && current_user.can_verify?
menu.item("Listings", manage_listings_path())
menu.item("Listing changes", needing_change_approval_manage_listings_path())
menu.item("Flagged Items", flagged_manage_listings_path())
menu.item("Transfers", manage_listing_transfers_path())
menu.item("Reviews", manage_listing_reviews_path())
end
if current_user && current_user.admin?
menu.item("Log", manage_verifications_path())
menu.item("Indexer Compensations", manage_compensations_path())
menu.item("Users", manage_users_path())
end
end%>
that splits out the below string
"<li>Listings</li> <li>Listing changes</li> <li>Flagged Items</li> <li>Transfers</li> <li>Reviews</li> <li>Log</li> <li>Indexer Compensations</li> <li>Users</li>"
I just get this string in my page. I wanted them to be menus nicely styled by CSS. I am just getting the above raw text in my page. How do I convert this string to be treated as HTML by the browser.
Please help
Here is the navigation class
class NavigationMenu < ActionView::Base
def initialize(params)
#params = params
end
def item(title, path, options={})
#items ||= Array.new
unless (route = Rails.application.routes.recognize_path(path,:method => options[:method]|| :get))
raise "Unrecognised path #{path}, are you sure it's in routes.rb?"
end
#items << content_tag(:li, link_to(title,path, :class => (#params[:controller] == route[:controller] && #params[:action] == route[:action])? 'active' : nil))
end
def output
return '' if #items.blank?
content_tag(:ul, #items.join("\n"), :id => 'navigation')
end
end
class Navigation
def self.with(params, &block)
menu = NavigationMenu.new(params)
yield menu
menu.output
end
end
You have to add a call to the raw method:
<%= raw ... %>
This is necessary, because in Rails 3 every string is escaped by default, unless you use the raw method.
It's like an inverse of the h method in Rails 2, where every string is unescaped by default, unless you use the h method.
Example:
This code in Rails 2...
<%= h "String which must be escaped" %>
<%= "String which must be output raw %>
... must be this in Rails 3:
<%= "String which must be escaped" %>
<%= raw "String which must be output raw %>
(Although an additional call to h doesn't do any harm in Rails 3)
You need to append .html_safe to the string - this will stop rails from escaping it when it's time to output text. Probably best to put it in the item method that you call repeatedly.
I recently wrote an article regarding XSS protection in Rails 3 when upgrading from Rails 2:
http://developer.uservoice.com/entries/upgrading-to-rails-3-printing-escaped-strings
The idea is to hook code to printing HTML so that we can determine when we are actually printing something we don't want to:
module ActionView
module Helpers
module TextHelper
def simple_format_with_double_escape_reporting(*args)
HtmlDoubleEscapeReporter.assert_sane(simple_format_without_double_escape_reporting(*args))
end
alias_method_chain :simple_format, :double_escape_reporting
end
module TagHelper
private
def content_tag_string_with_double_escape_reporting(*args)
HtmlDoubleEscapeReporter.assert_sane(content_tag_string_without_double_escape_reporting(*args))
end
alias_method_chain :content_tag_string, :double_escape_reporting
end
module UrlHelper
def link_to_with_double_escape_reporting(*args, &block)
HtmlDoubleEscapeReporter.assert_sane(link_to_without_double_escape_reporting(*args, &block))
end
alias_method_chain :link_to, :double_escape_reporting
end
end
end
Method HtmlDoubleEscapeReporter.assert_sane can be written, for example, like this:
class HtmlDoubleEscapeReporter
def self.assert_sane(str)
if (str.match(/<[a-z]/) || str.match(/&(quot|rarr|larr|amp|#)/)) &&
!str.match(/looks something you do not want to print/
send_problem_report('#{str}' looks something you do not want to print")
end
return str
end
end
Here, 'looks something you do not want to print' is used to prevent the possibility of infinite loops. The line send_problem_report('#{str}' looks something you do not want to print") can be replaced with a call to "debugger" (from ruby-debug gem) so that you are able to check the backtrace and see where the problem is coming from.
Here is the new class. At last... I got that bug.
class NavigationMenu < ActionView::Base
def initialize(params)
#params = params
end
def item(title, path, options={})
#items ||= Array.new
unless (route = Rails.application.routes.recognize_path(path,:method => options[:method]|| :get))
raise "Unrecognised path #{path}, are you sure it's in routes.rb?"
end
#items << content_tag(:li, link_to(title,path, :class => (#params[:controller] == route[:controller] && #params[:action] == route[:action])? 'active' : nil))
end
def output
#items = #items.join("\n").html_safe
return '' if #items.blank?
content_tag(:ul, #items, :id => 'navigation')
end
end
class Navigation
def self.with(params, &block)
menu = NavigationMenu.new(params)
yield menu
menu.output
end
end