I am having some problems creating a loop that could show the cheapest price.
Here is my controller:
def domain
country_codes = ['.dk', '.com', '.eu', '.net', '.org', '.biz', '.info', '.nu', '.name', '.se', '.fi', '.net', '.de', '.it'] # etc. could move this to a config if needed
#domain = params[:domain]
#results = {}
country_codes.each do |cc|
#results[cc] = Whois.whois(#domain + cc)
end
#pricedk = Domain.sort("dk ASC").first
#pricecom = Domain.sort("com ASC").first
#priceorg = Domain.sort("org ASC").first
#pricenet = Domain.sort("net ASC").first
#ETC...
end
My view:
<table border="0" bordercolor="#FFCC00" width="700" cellpadding="0" cellspacing="0">
<tr class="top">
<td class="checkdomain"></td>
<td>Name</td>
<td>Domain</td>
<td style="font-size:9px;"></td>
</tr>
<% #results.each_pair do |country_code, available| %>
<% klass = available.registered? ? "pinfo" : "info" %>
<tr>
<td><span class="<%= klass %>"></span></td>
<td><%= #domain + country_code %></td>
<td>PRICE HERE</td>
</tr>
<% end %>
</table>
I want to DRY the #pricecom, #pricedk, #priceorg up.
How do I include it in the #results loop?
When you have repetition like this, with many different instance variables, what you need to do is roll them all up into a single instance variable that's a Hash:
def domain
country_codes = %w[ dk com eu net org biz info nu name se fi net de it ]
#domain = params[:domain]
#results = { }
#prices = { }
country_codes.each do |cc|
#results[cc] = Whois.whois("#{#domain}.#{cc}")
#prices[cc.to_sym] = Domain.sort(cc).first
end
end
You'll see this pattern every so often. #pricesdk becomes #prices[:dk]
Related
I'm putting together a combo box or called the same as a select in rails, I put everything together but it gives me an error that tells me that I have a problem with the map inside the select, I'm using simple_form_for and I'm doing a map inside the collection inside the selector or called in simple_for associatio.
I copy the view and the controller
This view
<h1>HistContact#index</h1>
<p>Find me in app/views/hist_contact/index.html.erb</p>
<%= simple_form_for #histcontact, url:hist_contact_index_path do |f| %>
<% f.association :contact, collection: #contacts.map{|cont| [cont.name , cont.id]}%>
<%f.submit "buscar"%>
<% end %>
<table id = "client_table" class="table table-striped table-sm">
<thead>
<tr>
<th>Id</th>
<th>fecha</th
</tr>
</thead>
<tbody>
<% #histcontacts.each do |c|%>
<tr>
<td> <%= c.id %> </td>
<td> <%= c.created_at %></td>
</tr>
<% end %>
</tbody>
</table>
the controller
class HistContactController < ApplicationController
before_action :authenticate_user!
def index
#histcontacts = HistContact.all
#contacts = Contact.all
end
def new
#histcontact = HistContact.new
#contacts = Contact.new
end
def create
#histcontact = HistContact.find(contact_id: params[:contact])
end
private
def contactID(current_user)
client_id = Client.where(user_id: current_user.id)
contact_id = Contact.where(client_id: client_id.ids[0])
return contact_id
end
end
Thank you
According to error, you are trying to map a single object instead of an array of objects. Based on your controller code, the view file you shared is probably new.html.erb. To solve this problem you need do it like this:
def new
#histcontact = HistContact.new
#contacts = Contact.all
end
I have a task in my Rails app that can update a gallery album. This is passed an id that corresponds with an album on my Flickr account, it deletes all the photos attached to the album locally in the app and pulls them afresh from Flickr and updates the album name and title if required. This is required because I am currently working my way through all my photos re-tagging them all and this task will help pull those tags from Flickr to my site for searching and linking purposes.
I built an admin page that lists all my albums and each has an "Update Album" button. That looks like:
gallery.html.erb
<table class="striped">
<tr>
<th>Collections</th>
<th>Albums</th>
<th>Photo count</th>
<th>Flickr ID</th>
<th>Options</th>
</tr>
<% #collections.each do |c| %>
<tr>
<td><%= c.title %></td>
<td></td>
<td></td>
<td><%= c.flickr_id %></td>
<td></td>
</tr>
<% if c.has_albums? %>
<% c.albums.each do |a| %>
<tr class="<%= a.title.parameterize %>">
<td>↳</td>
<td>
<%= a.title %>
</td>
<td>
<%= a.photos.count %>
</td>
<td>
<%= a.flickr_id %>
</td>
<td class="this-one">
<%= link_to "Update",
admin_update_album_path(
album_flickr_id:a.flickr_id,
row: a.title.parameterize
),
"am-button": '',
method: :post,
remote: true
%>
</td>
</tr>
<% end %>
<% end %>
<% end %>
</table>
Because the task of updating took a while I thought putting it as a background job would be a good idea. Here's my controller and job:
gallery_controller.rb
class Admin::GalleryController < AdminController
def update_album
UpdateAlbumJob.perform_later(params[:album_flickr_id], params[:row])
end
end
update_album_job.rb
class UpdateAlbumJob < ApplicationJob
queue_as :default
after_perform do |job|
album = Album.find_by(flickr_id: job.arguments.first)
album.update_attribute(:updating, false)
puts job.arguments
ActionCable.server.broadcast 'album_updates_channel', content: 'Update complete', row: job.arguments[1], status: 'complete'
end
def perform(album_flickr_id, row)
require 'flickraw'
FlickRaw.api_key=ENV["FLICKR_API_KEY"]
FlickRaw.shared_secret=ENV["FLICKR_API_SECRET"]
flickr.access_token=ENV["FLICKR_OAUTH_TOKEN"]
flickr.access_secret=ENV["FLICKR_OAUTH_SECRET"]
# album_flickr_id = params[:album_flickr_id] or raise "No Album Flickr ID specified"
album = Album.find_by(flickr_id: album_flickr_id)
album.update_attribute(:updating, true)
ActionCable.server.broadcast 'album_updates_channel', content: 'Updating…', row: row, status: 'in-progress'
# Album.find_by(flickr_id: album_flickr_id).destroy if Album.find_by(flickr_id: album_flickr_id)
# Get tags
#flickr_tags_list = flickr.tags.getListUserRaw user_id: ENV["FLICKR_USER_ID"]
#tags_key = {}
#flickr_tags_list['tags'].each do |t|
#tags_key[t['clean'].to_sym] = t['raw'].first
end
# ========
# Work out parent collection
# This needs to cater for when there is NO parent collection
#collections = flickr.collections.getTree user_id: ENV["FLICKR_USER_ID"]
#parent_id = nil
def search_for_set_id_of_collection(set_id, collection, empty)
if collection["collection"]
collection.collection.each_with_index do |c|
search_for_set_id_of_collection(set_id, c, #parent_id)
end
end
if collection["set"]
collection["set"].each do |set|
if set["id"] == set_id
#parent_id = collection["id"]
end
end
end
end
#collections.each do |c|
search_for_set_id_of_collection(album_flickr_id, c, #parent_id)
end
# ========
Photo.where(album_id: album.id).destroy_all
Album.add_set_from_flickr(album_flickr_id, #parent_id, ENV["FLICKR_USER_ID"], #tags_key, true)
end
end
albumupdates.js:
const ActionCable = require('actioncable-modules');
const dotenv = require('dotenv')
dotenv.config()
const actionCable = ActionCable.createConsumer(process.env.WEBSOCKET_SERVER)
actionCable.subscriptions.create("AlbumUpdatesChannel", {
received: function(data) {
console.log('Hello from Action Cable');
if (data.status == 'in-progress') {
$('.' + data['row'] + ' td.this-one [am-Button]').hide();
$('.' + data['row'] + ' td.this-one').append(data['content']);
} else {
$('.' + data['row'] + ' td.this-one [am-Button]').show();
$('.' + data['row'] + ' td.this-one p').hide();
}
}
})
Basically, this is the first time i've just background jobs and action cable. I'm not 100% sure whether i've done this correctly but i wanted to give them a try and then ask on here for comments and suggestions. It sort of works ok but I have some questions:
Is this the best way of updating the table of albums with the status of the job? eg, "Updating..." and "Update complete!". I'd love to show an "Update Complete!" message but somehow remove that once it's been seen so just the button is showing again but unsure what path to go down to achieve that.
How would the live page updates work if i start an album updating, go away from the page and come back?
Also i'm unsure if my albumupdates.js file is set up correctly?
Just some comments and improvements to my code would be very helpful!
Thanks.
My code works perfectly, however, I know my approach isn't best practice practice. I would appreciate the effort of anyone who tries to explain in details on how I could refactor this code using either(presenters, decorators or poros) - I have no deep understanding of either yet.
Here is the code below:
In my events controller, I have a method called tickets_report defined as such
def tickets_report
#all_bookings = #event.bookings
#ticket_types = #event.ticket_types
#attendees = #event.attendees
end
then, I use the #ticket_types instance variable in my views to plot a table as follows:
<tbody>
<% grand_quantity = ticket_left = quantity_sold = total_price = total_amount = 0 %>
<% #tickets.each_with_index do |ticket, index| %>
<% remains = ticket.quantity.to_i - ticket.user_tickets.count.to_i
amount = ticket.price.to_f * ticket.user_tickets.count.to_i
grand_quantity += ticket.quantity
ticket_left += remains
quantity_sold += ticket.user_tickets.count
total_price += ticket.price.to_f
total_amount += amount
%>
<tr>
<td><%= index + 1%></td>
<td><%= ticket.name %></td>
<td><%= ticket.quantity %></td>
<td><%= remains %></td>
<td><%= ticket.user_tickets.count %></td>
<td><%= number_to_currency(ticket.price)%></td>
<td><%= number_to_currency(amount)%></td>
</tr>
<% end %>
<tr class="gtotal">
<td colspan="2">Grand Total</td>
<td><%= grand_quantity %></td>
<td><%= ticket_left %></td>
<td><%= quantity_sold %></td>
<td><%= number_to_currency(total_price)%></td>
<td><%= number_to_currency(total_amount)%></td>
</tr>
</tbody>
My problem is that calculations done in the view is really not a good thing, and this is how far I have gone trying to fix this myself
module Events
class Ticket
def initialize(ticket)
#ticket = ticket
end
def name
#ticket.name
end
def quantity
#ticket.quantity
end
def price
#ticket.price.to_f
end
def user_count
#ticket.user_tickets.count.to_i
end
def remains
#ticket.quantity.to_i - user_count
end
def amount
price * user_count
end
end
class TicketReportPresenter < Ticket
##grand_quantity = ##ticket_left = ##quantity_sold = 0
##total_price = ##total_amount = 0
def initialize(ticket)
#ticket = Ticket.new(ticket)
##grand_quantity += #ticket.quantity.to_i
##ticket_left += #ticket.remains
##quantity_sold += #ticket.user_count
##total_price += #ticket.price
##total_amount ++ #ticket.amount
end
class << self
def grand_quantity
##grand_quantity
end
def ticket_left
##ticket_left
end
def quantity_sold
##quantity_sold
end
def total_price
##total_price
end
def total_amount
##total_amount
end
end
end
end
The new tickets_report method in my controller
def tickets_report
#all_bookings = #event.bookings
#ticket_types = Events::TicketReportPresenter.new(#event.ticket_types.first)
#attendees = #event.attendees
end
However, things don't seem to be going right at this point. For instance I cannot call ActiveRecord relationships on the tickets object I defined. What is the best approach to refactor the logic present in the view, a detailed description and source code will suffice plus links to other resources. Thanks.
I may not be using the correct terminology but here goes..
I'm displaying IPS alerts on a dashboard app and there are many duplicate lines. For example, if one script kiddie is trying to brute force an RDP server, I could get 150 Alerts but could be slimmed down to about 5 because that's how many hosts they are going after. So I'm trying to remove the duplicate alerts, and I'm looking to use the sid, src_addr, and dst_addr as my metrics to determine if they are duplicates.
Currently I display #filtered_snort_detail_query using this code:
This is my view
<% if #filtered_snort_detail_query.count > 0 %>
<table>
<tr>
<th>Timestamp</th>
<th>Tag Info</th>
<th>Message</th>
</tr>
<% #filtered_snort_detail_query.each do |d|
text_msg = d['_source']['message']
if d['_source']['message'].nil?
end
%>
<tr>
<td class='timestamp'><%= d['_source']['#timestamp'].to_time %></td>
<td class='tags'><%= d['_source']['tags'] %></td>
<td class='message'><%= text_msg %></td>
</tr>
<% end %>
</table>
<% else %>
<div> No Results Returned. </div>
<% end %>
Here is my controller
if #es_snort_detail_query.count > 0
#filtered_snort_detail_query = Array.new
#es_snort_detail_query.each do |ips_detail|
next if ips_detail['_source']['type'] != 'snort-ips'
next if ips_detail['_source']['#timestamp'] < #ts
#filtered_snort_detail_query.push(ips_detail)
end
end
Here is what I think I need to do to get the metrics I need to compare lines in my controller.
I'm just not sure the best way to look at each line of #filtered_snort_detail_query and build a new array to display in my view using these parameters:
show me all lines, but not if sid_data, src_ip_data, and dst_ip_data happen two or more times.
if #es_snort_detail_query.count > 0
#filtered_snort_detail_query = Array.new
#es_snort_detail_query.each do |ips_detail|
next if ips_detail['_source']['type'] != 'snort-ips'
next if ips_detail['_source']['#timestamp'] < #ts
#filtered_snort_detail_query.push(ips_detail)
end
if #filtered_snort_detail_query.count > 0
ip_src = Array.new
ip_dst = Array.new
sid = Array.new
#filtered_snort_detail_query.each do |find_ip, find_sid|
unless find_ip.nil?
sid_data = find_sid.scan(/\[\d+\:\d+\:\d+\]/)
src_ip_data = find_ip.scan(/(?:[0-9]{1,3}\.){3}[0-9]{1,3}/)
dst_ip_data = find_ip.scan(/(?:[0-9]{1,3}\.){3}[0-9]{1,3}/)
sid.push(sid_data[0]) unless sid_data[0].nil?
ip_src.push(src_ip_data[0]) unless src_ip_data[0].nil?
ip_dst.push(dst_ip_data[1]) unless dst_ip_data[1].nil?
end
end
end
end
Sorry if I misunderstood the question.
If you have a bunch of objects in an array, and you want to remove duplicates based on a subset of their properties, you can use the uniq method with a block:
queries.uniq do |query|
[query.sid_data, query.src_ip_data, query.dst_ip_data]
end
It will compare the queries based on the array created in the block, and remove duplicates.
Go to http://www.compileonline.com/execute_ruby_online.php, copy and paste the code below, and click execute script in the top left.
queries = [
{ :a => "ab", :b => "ba" },
{ :a => "ab", :b => "xy" },
{ :a => "xy", :b => "xy" }
]
unique_queries = queries.uniq do |q|
q[:a]
end
puts unique_queries
See? The comparaison was done only based on the value of the :a key. That's the same principle.
Why doesn't this produce a table when called from my view? With fields_table(#user, ["id", "username"]) I am not getting the tbody's trs or tds, but I am getting everything else.
def fields_table(obj, fields)
return false if obj.nil?
content_tag(:table) do
thead = content_tag(:thead) do
content_tag(:tr) do
content_tag(:td, "Property") + content_tag(:td, "Value")
end
end
tbody = content_tag(:tbody) do
fields.each do |name|
content_tag(:tr) do
content_tag(:td, name) + content_tag(:td, obj.read_attribute(name))
end
end
end
thead + tbody
end
end
This code just iterates through the fields. It doesn't return anything, so the enclosing tbody isn't going to have anything to content.
tbody = content_tag(:tbody) do
fields.each do |name|
content_tag(:tr) do
content_tag(:td, name) + content_tag(:td, obj.read_attribute(name))
end
end
end
You need to return something like you do in the other parts of the code or change it to something like this:
tbody = content_tag(:tbody) do
fields.map do |name|
content_tag(:tr) do
content_tag(:td, name) + content_tag(:td, obj.read_attribute(name))
end
end.join
end
I would recommend rendering a partial using the collection argument, and built in rails goodness to do this type of operation. Im guessing you want the table headings to line up with the fields? You can still do that with something along the lines of the following (havent tested, but should work),
In your model define a class method or array as constant containing the attributes you want to display on the front end, e.g.
models/user.rb
VisibleFields = [:id, :username]
#workaround for toplevel class constant warning you may get
def self.visible_fields
User::VisibleFields
end
views/users/index.html.erb
<table>
<thead>
<tr>
<% User.visible_fields.each do |field| %>
<th><%= field.to_s.titleize %></th>
<% end %>
</tr>
</thead>
<tbody>
<%= render :partial => 'user', :collection => #users %>
</tbody>
</table>
**views/users/_user.html.erb**
<tr>
<% user.visible_fields.each do |field| %>
<td class="label"><%= field.to_s.titleize %></td><td class="value"><%= user.send(:field) %></td>
<% end %>
</tr>