host = Host.find(i)
a = host.open_ports
openPorts = []
a.split(",").each do |x|
openPorts << x
end
This is the set up were talking Ruby on Rails, so I set up my Ip address on iand grab all the open ports.String returned is then broken up via "," and added to an array.
Finding.all.each do |p|
openPorts.each do |y|
if p.port == y
Report.create(:port => p.port,
:risk_rating => p.risk_rating,
:finding => p.finding,
:implication => p.implication,
:recommendation => p.recommendation)
end
end
end
Iterates through findings table in the database and checks if the ports match the open ports array we created above. If there is a match we create a new report, based on the given value from the finding table.
The problem is does not create a new report even if there is a match.
Any help is appreciated.
Not sure if this helps but I wanted to show you how to clean up the implementation a bit.
host = Host.find(i)
# I am assuming Finding#port is an Integer
# if Finding#port is a String then just remove the .map(&:to_i) portion
open_ports = host.open_ports.split(",").map(&:to_i)
Finding.where(port: open_ports).each do |p|
Report.create(:port => p.port,
:risk_rating => p.risk_rating,
:finding => p.finding,
:implication => p.implication,
:recommendation => p.recommendation)
end
Lets start at the top
String#split returns an Array so no need to push it into a new one. It does however create an Array of Strings so if you need integers #map(&:to_i) will do this for you. I am assuming this is the current issue which is comparison of a string with integer for example "80" == 80 #=> false
Next rather than loop through all the Findings why not just pull out the one's with matching ports? Finding.where(port: open_ports) this will generate a query like SELECT findings.* FROM findings where findings.port IN (YOUR_OPEN_PORTS_ARRAY)
Then we just create the reports from this limited list instead of the loop through all Findings and then a loop through open_ports as well.
Related
I'm new to Ruby and I am building a web scraper. I have a variable that is assigned a value if a conditional is true.
The problem is that the value of the variable is really long and I'd like to avoid repeating myself with these long values.
I am using conditionals because the number of data that exists is not a static figure.
#Grab the top 3 comps if they exist
#comp1
if b.element(:xpath => '/html/body/form/div[3]/div[6]/table/tbody/tr/td/div[2]/div[3]/div[3]/div/div/div[1]/table/tbody/tr[1]/td[13]/span').exists?
comp1 = b.element(:xpath => '/html/body/form/div[3]/div[6]/table/tbody/tr/td/div[2]/div[3]/div[3]/div/div/div[1]/table/tbody/tr[1]/td[13]/span')
end
#comp2
if b.element(:xpath => '/html/body/form/div[3]/div[6]/table/tbody/tr/td/div[2]/div[3]/div[3]/div/div/div[1]/table/tbody/tr[2]/td[13]/span').exists?
comp2 = b.element(:xpath => '/html/body/form/div[3]/div[6]/table/tbody/tr/td/div[2]/div[3]/div[3]/div/div/div[1]/table/tbody/tr[2]/td[13]/span')
end
#comp3
if b.element(:xpath => '/html/body/form/div[3]/div[6]/table/tbody/tr/td/div[2]/div[3]/div[3]/div/div/div[1]/table/tbody/tr[3]/td[13]/span').exists?
comp3 = b.element(:xpath => '/html/body/form/div[3]/div[6]/table/tbody/tr/td/div[2]/div[3]/div[3]/div/div/div[1]/table/tbody/tr[3]/td[13]/span')
end
Is there a way to decrease it the length of that such as
if "telement with really long xpath location on the webpage that we are checking to see if it is true ".exists?
x = "That conditional referenced above"
end
Since you're just replacing a single number in that long xpath selector you can use a template string:
elements = (1..3).map do |x|
b.element(
xpath: '/html/body/form/div[3]/div[6]/table/tbody/tr/td/div[2]/div[3]/div[3]/div/div/div[1]/table/tbody/tr[%d]/td[13]/span' % x
)
end.select(&:exists?)
See Kernel#sprintf for the options which are pretty much identical to the venerable C sprintf function.
Break up the string, either literally, or logically:
# literally
table_xpath = '/html/body/form/div[3]/div[6]/table/tbody/tr/td/div[2]/div[3]/div[3]/div/div/div[1]/table'
if b.element(:xpath => "#{table_xpath}/tbody/tr[1]/td[13]/span").exists?
#...
end
# logically
table = b.element(xpath: '/html/body/form/div[3]/div[6]/table/tbody/tr/td/div[2]/div[3]/div[3]/div/div/div[1]/table')
if table.element(xpath: "tbody/tr[1]/td[13]/span").exists?
end
break it up as many or as few times as you feel like to make the code read well.
You can directly write WATIR CODE as shown below, you have to use elements instead of element
b.elements(:xpath => '/html/body/form/div[3]/div[6]/table/tbody/tr/td/div[2]/div[3]/div[3]/div/div/div[1]/table/tbody/tr')
.take(3)
.map{|tr|tr.element(xpath: "./td[13]/span")}
But still, the above code is not optimized, you can write the below code Once you located the table, For the below code, I assume the table number is 2.
b.table(index: 2)
.rows
.to_enum
.take(3)
.map{|row| row.cell(index: 13).span}
My database will not update my active_quests. All I am trying to do is replace one array of hashes with another, updated array of hashes. I assumed would be the simplest way of handling this. Here's the code:
# construct the query
query = Player.where( :_id => player_id).fields( :xp, :lvl_prgrssns, :active_quests, :completed_quests )
# get the player
player = query.first
if !player.nil?
return_val = player.set( :active_quests => [{"quest_id" => "123"}, {"quest_id" => "456"}])
logger.debug "return_val = "+return_val.to_s # comes out as 180
end
My understanding is that, if the return from a set is positive, that means that the set was successful. It returns as 180 in this simplified case but the active_quests never get updated on the player. I can go into the mongo console and execute this:
db.players.update({_id:ObjectId("50756b1896f4f5121a00000a")}, {$set:{active_quests:[{"quest_id":"1"}, {"quest_id":"2"}] }});
and active_quests will update as expected but no matter what I try in rails the update appears to go through but nothing updates.
Here are some of the many alternatives I have tried (all have been tried with and without .to_mongo and with and without player.save after them):
Player.where( :_id => params[:player_id] ).update(:active_quests => active_quests_list.to_mongo)
player.update_attributes(:active_quests => active_quests_list.to_mongo)
player_update = player.as_json
player_update["active_quests"] = active_quests_list
player.update_attributes(player_update)
return_val = query.update( "$set" => {:active_quests => player.active_quests.to_mongo} )
return_val = query.update( {:_id => params[:player_id]}, {"$set" => {:active_quests => active_quests_list.to_mongo}})
I'm hoping someone here might know what I am doing wrong.
After further investigation, it turns out that this was a problem relating to how the player variable was being updated outside of the function.
The following lines will update the record in this case (both in-memory and in the database)
player[:active_quests] << #active_quests_list
player.push_all(:active_quests => player.active_quests)
However, the player variable was local to this function in this case, and was being updated again after the function returned.
This was only discovered after careful examination of the output of "mongod -vvvvv".
I have a service I query and I get data I filter through and create a an array of records.
Unless I missed something, ActiveResource::Base does not qualify since the access to the service is not via rest and I can't use the raw data as delivered.
I am displaying the data in a table and use will_paginate to page the data. But I am not currently married to will_paginate.
I do need to sort the columns as well as paginate.
I have found two version of ujs_sort_helper.
https://github.com/pengwynn/ujs_sort_helper
https://github.com/sikachu/ujs_sort_helper
I am trying to understand:
- http://javathehutt.blogspot.com/2009/06/mo-simple-sortable-tables-in-rails.html
What have other done in rails 3? Or is one of the ujs_sort_helper packages just he correct way to go.
In term of data refresh, this is a dashbaord. Multiple data source will address the various DIVs.
Also, I am a Rails noob. But not a programming noob.
You could use meta_search's sort_link if you wish.
I like it because it also does filtering incredibly easy with meta_where.
You can also make the behavior through ajax by adding the data-remote attribute to 'a.sort_link' (i have done that through javascript).
I would welcome the maintainer of ujs_sort_helper to comment. Just a bug here and there in the rails 3 version of the code. Now ujs_sort_helper works, for me.
What I have not done is create ANOTHER branch on this package. I emailed the file to the author.
sort order now compares symbols, instead of symbol to string.
def sort_order(column, initial_order='asc')
#safe since to_sm on a sym is a nil operation. At least for now.
if session[#sort_name][:key].to_sym == column.to_sym
session[#sort_name][:order].downcase == 'asc' ? 'desc' : 'asc'
else
initial_order
end
end
The icon us set via the current order value. The sort clause should be the opposite. So show down arrow for the list being displayed in ascending order, but the 'url' is set to redisplay the table in descending order.
I have no clue what the :q symbol is supposed to be used for.
def sort_header_tag(column, options = {})
options[:initial_order].nil? ? initial_order = "asc" : initial_order = options[:initial_order]
key = session[#sort_name][:key].to_sym
order = sort_order(column, initial_order)
caption = options.delete(:caption) || column.to_s.titleize
url = { :sort_key => column, :sort_order => order, :filter => params[:filter]}
url.merge!({:q => params[:q]}) unless params[:q].nil?
content_tag('th', link_to(caption, url, :class=>session[#sort_name][:order] ), :class => "sort_link #{order if key == column}")
end
This is a snippet of code from an update method in my application. The method is POSTed an array of user id's in params[:assigned_ users_ list_ id]
The idea is to synchronise the DB associations entries with the ones that were just submitted, by removing the right ones (those that exist in the DB but not the list) and adding the right ones (vise-versa).
#list_assigned_users = User.find(:all, :conditions => { :id => params[:assigned_users_list_id]})
#assigned_users_to_remove = #task.assigned_users - #list_assigned_users
#assigned_users_to_add = #list_assigned_users - #task.assigned_users
#assigned_users_to_add.each do |user|
unless #task.assigned_users.include?(user)
#task.assigned_users << user
end
end
#assigned_users_to_remove.each do |user|
if #task.assigned_users.include?(user)
#task.assigned_users.delete user
end
end
It works - great!
My first questions is, are those 'if' and 'unless' statements totally redundant, or is it prudent to leave them in place?
My next question is, I want to repeat this exact code immediately after this, but with 'subscribed' in place of 'assigned'... To achieve this I just did a find & replace in my text editor, leaving me with almost this code in my app twice. That's hardly in keeping with the DRY principal!
Just to be clear, every instance of the letters 'assigned' becomes 'subscribed'. It is passed params[:subscribed_ users_ list_ id], and uses #task.subscribed_ users.delete user etc...
How can I repeat this code without repeating it?
Thanks as usual
You don't need if and unless statements.
As for the repetition you can make array of hashes representing what you need.
Like this:
[
{ :where_clause => params[:assigned_users_list_id], :user_list => #task.assigned_users} ,
{ :where_clause => params[:subscribed_users_list_id], :user_list => #task.subscribed_users}
] each do |list|
#list_users = User.find(:all, :conditions => { :id => list[:where_clause] })
#users_to_remove = list[:user_list] - #list_users
#users_to_add = #list_users - list[:user_list]
#users_to_add.each do |user|
list[:user_list] << user
end
#users_to_remove.each do |user|
list[:user_list].delete user
end
end
My variable names are not the happiest choice so you can change them to improve readability.
I seem to be missing something here, but aren't you just doing this?
#task.assigned_users = User.find(params[:assigned_users_list_id])
I'm doing this:
#snippets = Snippet.find :all, :conditions => { :user_id => session[:user_id] }
#snippets.each do |snippet|
snippet.tags.each do |tag|
#tags.push tag
end
end
But if a snippets has the same tag two time, it'll push the object twice.
I want to do something like if #tags.in_object(tag)[...]
Would it be possible? Thanks!
I think there are 2 ways to go about it to get a faster result.
1) Add a condition to your find statement ( in MySQL DISTINCT ). This will return only unique result. DBs in general do much better jobs than regular code at getting results.
2) Instead if testing each time with include, why don't you do uniq after you populate your array.
here is example code
ar = []
data = []
#get some radom sample data
100.times do
data << ((rand*10).to_i)
end
# populate your result array
# 3 ways to do it.
# 1) you can modify your original array with
data.uniq!
# 2) you can populate another array with your unique data
# this doesn't modify your original array
ar.flatten << data.uniq
# 3) you can run a loop if you want to do some sort of additional processing
data.each do |i|
i = i.to_s + "some text" # do whatever you need here
ar << i
end
Depending on the situation you may use either.
But running include on each item in the loop is not the fastest thing IMHO
Good luck
Another way would be to simply concat the #tags and snippet.tags arrays and then strip it of duplicates.
#snippets.each do |snippet|
#tags.concat(snippet.tags)
end
#tags.uniq!
I'm assuming #tags is an Array instance.
Array#include? tests if an object is already included in an array. This uses the == operator, which in ActiveRecord tests for the same instance or another instance of the same type having the same id.
Alternatively, you may be able to use a Set instead of an Array. This will guarantee that no duplicates get added, but is unordered.
You can probably add a group to the query:
Snippet.find :all, :conditions => { :user_id => session[:user_id] }, :group => "tag.name"
Group will depend on how your tag data works, of course.
Or use uniq:
#tags << snippet.tags.uniq