In my application I have a WebsiteAd model & website_ads table where I have all my websites ads that I can control from my admin.
Currently in a page I do 1 query for each ad to database and in my view as well to see if the ad is active.
In my controller:
# START - Desktop ads
def ads_desktop_tablet
#header_desktop_tablet = ad_placement('header_desktop-tablet')
#footer_desktop_tablet = ad_placement('footer_desktop-tablet')
#footer_desktop_tablet_c = ad_placement('footer_desktop-tablet_C')
#desktop_tablet_b1 = ad_placement('desktop-tablet_B1')
#desktop_tablet_b2 = ad_placement('desktop-tablet_B2')
#desktop_tablet_b3 = ad_placement('desktop-tablet_B3')
#desktop_tablet_s1 = ad_placement('desktop-tablet_S1')
#desktop_inline_banner = ad_placement('desktop_inline_banner')
#desktop_inline_video = ad_placement('desktop_inline_video')
#desktop_tablet_b2_c = ad_placement('desktop-tablet_B2_C')
#desktop_tablet_b3_c = ad_placement('desktop-tablet_B3_C')
#desktop_tablet_s1_c = ad_placement('desktop-tablet_S1_C')
#desktop_tablet_l1 = ad_placement('desktop-tablet_L1')
end
# END - Desktop ads
# START - Mobile ads
def ads_mobile
#header_mobile = ad_placement('header_mobile')
#footer_mobile = ad_placement('footer_mobile')
#mobile_b1 = ad_placement('mobile_B1')
#mobile_b2 = ad_placement('mobile_B2')
#mobile_b3 = ad_placement('mobile_B3')
#mobile_s1 = ad_placement('mobile_S1')
#mobile_inline_banner = ad_placement('mobile_inline_banner')
#mobile_b3_c = ad_placement('mobile_B3_C')
end
# END - Mobile ads
In my helper:
def ad_placement(placement)
WebsiteAd.where(placement: placement).first
end
# I have a method/`def` for each ad like below
def ad_desk_s1_active?
if desktop_tablet_s1.status == true
desktop_tablet_s1.ad_tag.html_safe
end
end
In my view:
= ad_desk_s1_active?
I know this is not a good practice and right way to do. How can I make this more efficient and much less code and db queries?
You can use index_by
#ads = WebsiteAd.all.index_by(&:placement)
or get only the required ads
placements = %w(header_mobile footer_mobile)
#ads = WebsiteAd.where(placement: placements).index_by(&:placement)
Which results in a hash
#header_mobile = #ads['header_mobile']
or just use #ads in the view directly
<%= #ads['header_mobile'] %>
Related
Would this work? I want to do something like coins transfer
#logs = Logs.new(log_params)
#logs.save
#tt = Users.where(email: params[:email]).update(money: Users.find(current_user.id)['money'] - params[:money])
#tt.save
#wr = Users.find(current_user.id).update(money: Users.where(email: params[:email])['money'] + params[:money])
#wr.save
I don't know if you are planning to display those values in your views, but you could do something like this:
sender = Users.where(email: params[:email]).first
# This returns the user
recipient = Users.find(current_user.id)
# or just current_user if it inherit from the User class
money_to_substract = recipient.money - params[:money]
money_to_sum = recipient.money + params[:money]
Then your transsaction would be a bit dryier
User.transaction do
#logs = Logs.new(log_params)
#tt = sender.update(money: money_to_substract)
# update saves to the database so no need to call save
# #tt.save
#wr = recipient.update(money: money_to_sum)
# update saves to the database so no need to call save
# #wr.save
end
But IMHO, I would do something like this:
models/User.rb
class User < ActiveRecord::Base
...
def sends_money(amount)
money_to_substract = self.money - amount
update(money: money_to_substract)
end
def receives_money(amount)
money_to_sum = self.money + amount
update(money: money_to_sum)
end
...
end
In your controller
amount = params[:money].to_i
User.transaction do
#logs = Logs.new(log_params)
#tt = sender.sends_money(amount)
#wr = recipient.receives_money(amount)
end
Which makes things easier to read and follow through your code.
Hope this helps!
I have three fields start date , end date and , issue tracker group if I select only group then all records of that group should come from issue request table but when I select date then it should display specific date records .
Controller Code -
def group_report_list
#start = params[:date].to_date
#en = params[:to_date].to_date
#issue_tracker_group = IssueTrackerGroup.find(params[:id])
#issue_requests = IssueRequest.where(issue_tracker_group_id: #issue_tracker_group.id,date: #start..#en)
one way is using normal if..else condition.
def group_report_list
#start = params[:date].to_date unless params[:date].nil?
#en = params[:to_date].to_date unless params[:to_date].nil?
#issue_tracker_group = IssueTrackerGroup.find(params[:id])
unless #start.nil? or #en.nil?
#issue_requests = IssueRequest.where(issue_tracker_group_id: #issue_tracker_group.id,date: #start..#en)
else
#issue_requests = IssueRequest.where(issue_tracker_group_id: #issue_tracker_group.id)
end
end
if you feel this is too lengthy code, you can use the code below
def group_report_list
#start = params[:date]
#en = params[:to_date]
#issue_tracker_group = IssueTrackerGroup.find(params[:id])
condition = "issue_tracker_group_id = #{#issue_tracker_group.id}"
condition += " AND date BETWEEN '#{#start.to_date}' AND '#{#en.to_date}' " unless #start.nil? or #en.nil?
#issue_requests = IssueRequest.where(condition)
end
I have created Rails application and I have used lots of instance variables and most of them are not required in the views. Do I need to replace the unused instance variables for improving the performance?
Sample code:
def show
custom_fields_data = fetch_custom_field_data
#selected_custom_fields_opt_from_view = []
if custom_fields_data.present?
#listings = #listing.category.listings.where("price_cents!=? AND open= ?",0,true).reject { |l| l.author.main_admin? }
#selected_custom_fields_opt_from_view = custom_fields_data.map do |custom_field_data|
CustomField.find(custom_field_data[0]).options.find(custom_field_data[1])
end
#listings.each do |listing|
# array to store the selected a custom field's option from Database
selected_custom_fields_opt_from_db = []
listing.custom_field_values.each do |custom_field_value|
selected_custom_fields_opt_from_db.push(custom_field_value.selected_options.first)
end
if selected_custom_fields_opt_from_db.uniq.sort == #selected_custom_fields_opt_from_view.uniq.sort || (#selected_custom_fields_opt_from_view - selected_custom_fields_opt_from_db).empty?
similar_listing.push(listing)
end
end
#listings = similar_listing
end
#listing_with_filters = similar_listing.present? ? #listings.first : #listing
#selected_tribe_navi_tab = "home"
unless current_user?(#listing.author)
#listing.increment!(:times_viewed)
end
#current_image = if params[:image]
#listing.image_by_id(params[:image])
else
#listing.listing_images.first
end
#prev_image_id, #next_image_id = if #current_image
#listing.prev_and_next_image_ids_by_id(#current_image.id)
else
[nil, nil]
end
payment_gateway = MarketplaceService::Community::Query.payment_type(#current_community.id)
process = get_transaction_process(community_id: #current_community.id, transaction_process_id: #listing.transaction_process_id)
form_path = new_transaction_path(listing_id: #listing.id)
delivery_opts = delivery_config(#listing.require_shipping_address, #listing.pickup_enabled, #listing.shipping_price, #listing.shipping_price_additional, #listing.currency)
#category = #listing.category
#template_listing = #category.template_listing
if #current_user
# For Pivot table
#selected_custom_field = params[:custom_field] if params[:custom_field]
#listing_for_pivot = Listing.new
#listing_images = #listing.listing_images
#shape = get_shape(#listing.listing_shape_id)
#unit_options = ListingViewUtils.unit_options(#shape[:units], unit_from_listing(#template_listing)).first if #shape
#custom_field_questions = #category.custom_fields
#numeric_field_ids = numeric_field_ids(#custom_field_questions)
#category_tree = CategoryViewUtils.category_tree(
categories: ListingService::API::Api.categories.get(community_id: #current_community.id)[:data],
shapes: get_shapes,
locale: I18n.locale,
all_locales: #current_community.locales
)
if #template_listing.present?
#listing_for_pivot.title = #template_listing.title
#listing_for_pivot.description = #template_listing.description
#listing_images = #template_listing.listing_images if #template_listing.listing_images.present?
#listing_for_pivot.listing_shape_id = #template_listing.listing_shape_id
end
if (#current_user.location != nil)
temp = #current_user.location
temp.location_type = "origin_loc"
#listing_for_pivot.build_origin_loc(temp.attributes)
else
#listing_for_pivot.build_origin_loc(:location_type => "origin_loc")
end
#custom_field_area = CategoryCustomField.where(category_id: #category.id, custom_field_id: #category.custom_fields.pluck(:id))
#row = #category.custom_field_row
#row = #custom_field_area.first.custom_field if #row.nil? && #custom_field_area.first
#column = #category.custom_field_column
#column = #custom_field_area.second.custom_field if #column.nil? && #custom_field_area.second
#filters = #category.custom_field_filters
#filters = #custom_field_area.all.from(1).map { |category_custom_field| category_custom_field.custom_field } if #filters.nil? && #custom_field_area.size > 2
#selected_value_for_filter = []
if #filters.present?
if #selected_custom_field
#filters.each do |filter|
if (#selected_custom_field["#{filter.id.to_s}_"])
#selected_value_for_filter.push(filter.options.find(#selected_custom_field["#{filter.id.to_s}_"]))
else
#selected_value_for_filter.push(filter.options.first)
end
end
else
#filters.each do |filter|
#selected_value_for_filter.push(filter.options.first)
end
end
end
# Pivot table section end
end
#applicant = #category.listings.pluck(:author_id).uniq
#suggested_business_accounts = #category.people.where("people.id NOT IN (?)", #applicant);
if #suggested_business_accounts.present?
#business_locations =
#suggested_business_accounts.map do |person|
person.location
end
#business_locations.compact!
end
render locals: {
form_path: form_path,
payment_gateway: payment_gateway,
# TODO I guess we should not need to know the process in order to show the listing
process: process,
delivery_opts: delivery_opts,
listing_unit_type: #listing.unit_type
}
end
It is not recommended to use instance variables if you don't want to send them to views. The scope of the variables should be narrowest, therefore in your case if you are not using instance variables in the views you should convert them to local.
Using instance variables instead of local variables is a bad idea at least memory-wise.
Instance variable exists while the object that holds it exists. On the contrary, local variable exists only inside method/block it is defined.
Garbage collector does not care whether you use instance variable elsewhere beyond the method or not.
Thus, if you have instance variables, which you only intend to use within the method - change them to local ones.
I have the following two methods for a Number model.
def track
number = sanitize(tracking)
case determine_type(number)
when 'UPS'
tracker = ups.track(:tracking_number => number)
self.carrier = Carrier.where(:name => 'UPS').first
self.service = tracker.service_type
self.destination_country = tracker.destination_country
self.destination_state = tracker.destination_state
self.destination_city = tracker.destination_city
self.origin_country = tracker.origin_country
self.origin_state = tracker.origin_state
self.origin_city = tracker.origin_city
self.signature = tracker.signature_name
self.scheduled_delivery = tracker.scheduled_delivery_date
self.weight = tracker.weight
tracker.events.each do |event|
new_event = Event.new
new_event.number = self
new_event.city = event.city
new_event.state = event.state
new_event.postalcode = event.postal_code if event.postal_code
new_event.country = event.country
new_event.status = event.name
new_event.status_code = event.type
new_event.occured_at = event.occurred_at
new_event.save
end
end
save
end
def update_number
case determine_type(number)
when 'UPS'
tracker = ups.track(:tracking_number => tracking)
self.carrier = Carrier.where(:name => 'UPS').first
self.service = tracker.service_type
self.destination_country = tracker.destination_country
self.destination_state = tracker.destination_state
self.destination_city = tracker.destination_city
self.origin_country = tracker.origin_country
self.origin_state = tracker.origin_state
self.origin_city = tracker.origin_city
self.signature = tracker.signature_name
self.scheduled_delivery = tracker.scheduled_delivery_date
self.weight = tracker.weight
last_event = self.events.ordered.first.occured_at
tracker.events.each do |event|
if last_event and (event.occurred_at > last_event)
new_event = Event.new
new_event.number = self
new_event.city = event.city
new_event.state = event.state
new_event.postalcode = event.postal_code if event.postal_code
new_event.country = event.country
new_event.status = event.name
new_event.status_code = event.type
new_event.occured_at = event.occurred_at
new_event.save
end
end
end
save
end
As you can see, a lot of code is duplicated. And the problem becomes when I start adding the dozen or so other carriers (FedEx, USPS, DHL, etc)...my Number model gets big and hairy fast.
The only real difference between track and update_number is that update_number as an if comparison around the events to check if the events from the carrier are more recent than the latest events I have stored in the database, using that if last_event and (event.occurred_at > last_event) line.
So how can I clean up this code so my model doesn't get so fat?
A couple of things I would suggest:
Look at the Strategy Pattern, even though Ruby doesn't have interfaces, but it'll give you some ideas on how to better design this functionality (google for Strategy Pattern for Ruby to find alternatives). Basically, you'd want to have separate classes to handle your switch case statements and call the appropriate one at runtime.
Try to separate the tracker handling code from the events handling code. E.g., I would consider moving the event creation/saving logic for each of the tracker events to a separate class (or even to the Tracker entity, if you have one).
Hope this helps.
This should be solved using the Strategy pattern. For each possible tracker (DHL, UPS, ...) that will handle the creating and updating appropriately.
So that would become something like:
class Number
def track
tracker = get_tracker(tracking)
tracker.create_tracking(self)
save
end
def update_number
tracker = get_tracker(tracking)
tracker.update_tracking(self)
save
end
def get_tracker(tracking)
tracking_number = sanitize(tracking)
case determine_type(tracking_number)
when 'UPS'
UPSTracker.new(tracking_number)
when 'DHL'
DHLTracker.new(tracking_number)
end
end
end
class UPSTracker
def initialize(tracking_number)
#tracking_number = tracking_number
end
def create_tracking(number)
tracker = ups.track(:tracking_number => number)
update_number_properties(number, tracking)
# store events
tracker.events.each do |event|
create_new_event(event)
end
end
def update_tracking(number)
tracker = ups.track(:tracking_number => number)
update_number_properties(number, tracking)
last_event = self.events.ordered.first.occured_at
tracker.events.each do |event|
if last_event and (event.occurred_at > last_event)
create_new_event(event)
end
end
end
protected
def update_number_properties
number.carrier = Carrier.where(:name => 'UPS').first
number.service = tracker.service_type
number.destination_country = tracker.destination_country
number.destination_state = tracker.destination_state
number.destination_city = tracker.destination_city
number.origin_country = tracker.origin_country
number.origin_state = tracker.origin_state
number.origin_city = tracker.origin_city
number.signature = tracker.signature_name
number.scheduled_delivery = tracker.scheduled_delivery_date
number.weight = tracker.weight
end
def create_new_event
new_event = Event.new
new_event.number = self
new_event.city = event.city
new_event.state = event.state
new_event.postalcode = event.postal_code if event.postal_code
new_event.country = event.country
new_event.status = event.name
new_event.status_code = event.type
new_event.occured_at = event.occurred_at
new_event.save
end
end
This code could be further improved, I imagine the creating of events and trackings will be shared over the different carriers. So a shared base-class maybe. Secondly, in two methods inside Number we call the get_tracker: probably this tracker can be decided upon creation time (of the Number-instance) and should be fetched once and stored inside an instance variable.
Furthermore I would like to add that names should be meaningful, so a class Number does not sound meaningful enough to me. A name should express intent, and preferably match the names and concepts from your problem domain.
Something about your code doesn't make sense to me, the organization is a little strange and I don't have enough context on what your app looks like. The OOP-ish way to accomplish something like this in rails is pretty easy; you could also roll your own Strategy, Adapter, or even a Builder pattern to do this.
But, there is some low hanging fruit, you can refactor your code so the common parts are less obtrusive -- this is a little better but, create_events is still very case'y:
def track
create_events
end
def update_number
create_events {|e| last_event and (event.occurred_at > last_event) }
end
def create_events(&block)
case determine_type(number)
when 'UPS'
tracker = ups.track(:tracking_number => tracking)
self.carrier = Carrier.where(:name => 'UPS').first
self.assign_tracker(tracker)
end
tracker.events.each do |e|
self.create_event(e) unless (block_given? && !block.call(e))
end
save
end
def assign_tracker(tracker)
self.service = tracker.service_type
self.destination_country = tracker.destination_country
self.destination_state = tracker.destination_state
self.destination_city = tracker.destination_city
self.origin_country = tracker.origin_country
self.origin_state = tracker.origin_state
self.origin_city = tracker.origin_city
self.signature = tracker.signature_name
self.scheduled_delivery = tracker.scheduled_delivery_date
self.weight = tracker.weight
end
def create_event(event)
new_event = Event.new
new_event.number = self
new_event.city = event.city
new_event.state = event.state
new_event.postalcode = event.postal_code if event.postal_code
new_event.country = event.country
new_event.status = event.name
new_event.status_code = event.type
new_event.occured_at = event.occurred_at
new_event.save
end
i want to get the 10 google search results links (href) using mechanize so i wrote this code, but the code does not return the right google search results, what should i write?
#searchword = params[:q]
#sitesurl = Array.new
agent = Mechanize.new
page = agent.get("http://www.google.com")
search_form = page.form_with(:name => "f")
search_form.field_with(:name => "q").value = #searchword.to_s
search_results = agent.submit(search_form)
count = 0
c = 0
while c < 10
if (search_results/"li")[count].attributes['class'].to_s == "g knavi"
site = (search_results/"li")[count]
code = (site/"a")[0].attributes['href']
#sitesurl << code
c += 1
end
count += 1
end
Something like this should work:
#searchword = params[:q]
#sitesurl = Array.new
agent = Mechanize.new
page = agent.get("http://www.google.com")
search_form = page.form_with(:name => "f")
search_form.field_with(:name => "q").value = #searchword.to_s
search_results = agent.submit(search_form)
(search_results/"li.g").each do |result|
#sitesurl << (result/"a").first.attribute('href') if result.attribute('class').to_s == 'g knavi'
end
This is the updated one for now. Tested and work's fine
require 'rubygems'
require 'mechanize'
require 'hpricot'
agent = Mechanize.new
agent.user_agent_alias = 'Linux Firefox'
page = agent.get('http://google.com/')
google_form = page.form('f') google_form.q = 'your search'
page = agent.submit(google_form)
page.links.each do |link|
if link.href.to_s =~/url.q/
str=link.href.to_s
strList=str.split(%r{=|&})
url=strList[1]
# if You need cached url's then just remove this condition and simply use URL's
if ! url.include? "webcache"
puts url
end
end
end
Just create a new array and push the url's to array.
It's not working now, I suppose that could be because Google recently changes their HTML in the search results and URLs.
Nowadays, the answers above don't work anymore. We have released our own gem that is easy to use and allow custom locations:
query = GoogleSearchResults.new q: "coffee", location: "Portand"
hash_results = query.get_hash
Repository: https://github.com/serpapi/google-search-results-ruby