Why is my service not changing my instance variable? - ruby-on-rails

My service is supposed to match the current user with an opponent. I have a method in my service that is supposed to find this opponent but it's not saving it in my controller. I realize this is a very basic question but I'm very new to rails, thank you!
Here is my service:
class MatchUser
attr_accessor :user_params
def initialize(user_params)
#user_params = user_params
end
def match(opponent)
return false if user_params[:matched] == true
#unmatched_users = User.where(matched: false)
#unique_unmatched_users = #unmatched_users.where.not(id: user_params[:id])
#same_league_unmatched_users = #unique_unmatched_users.where(league_id:
user_params[:league_id])
return false if #same_league_unmatched_users.empty?
opponent = #same_league_unmatched_users.sample
opponent.faceoff_date = Time.now
user_params[:faceoff_date] = Time.now
opponent.save!
end
end
Here is the part in my controller where I'm getting an error when I try to assign #matched_user_team because #matched_user is nil
#user = current_user
#matching = MatchUser.new(#user)
if #matching.match(#matched_user)
#matched_user_team = #matched_user.teams.last.chars
end

Related

Is using local variable instead of instance variable improve the performance(save memory) in Rails?

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.

Stack level too deep on user.save

I want to assign a confirmation code to my users while creating one. And I also titleize some columns before saving-updating them. So my user.rb looks like this (it may be a bit messy):
// user.rb
*** some code ***
before_save { titleize_column(:name)
titleize_column(:surname)
capitalize_column(:complaints)
capitalize_column(:education)
capitalize_column(:job)
capitalize_column(:complaintsdetails)
capitalize_column(:prediagnosis)
capitalize_column(:existingdiagnosis)
capitalize_column(:knownilnessesother)
capitalize_column(:usedmedicine)
capitalize_column(:operation)
capitalize_column(:trauma)
capitalize_column(:allergy)
capitalize_column(:otherhabits)
capitalize_column(:motherother)
capitalize_column(:fatherother)
capitalize_column(:siblingsother)
}
before_save :generate_confirmation_code
protected
def generate_confirmation_code
unless self[:confirmed]
if(self[:type] == 'Patient')
update_attribute :confirmation_code, SecureRandom.urlsafe_base64(20)
update_attribute :confirmed, false
else
update_attribute :confirmed, true
end
end
end
protected
def capitalize_column(attr)
unless self[attr].nil?
self[attr] = Unicode::capitalize self[attr]
end
end
protected
def titleize_column(attr)
unless self[attr].nil?
words = self[attr].split
words.each_with_index do |v,i|
words[i] = Unicode::capitalize v
end
self[attr] = words.join(" ")
end
end
I'm using separate methods for titleizing and capitalizing columns because they may be nil when first creating a user, so I'm checking if it is null or not in those methods. This structure works fine on a normal signup with strong parameters. However, if I try to use twitter signup with the method below, it gives me the error 'stack level too deep' and I can see that it calls the generate_confirmation_code 123 times from the application trace and then these happens:
app/models/user.rb:83:in each'
app/models/user.rb:83:ineach_with_index'
app/models/user.rb:83:in titleize_column'
app/models/user.rb:20:inblock in '
app/models/user.rb:64:in generate_confirmation_code' (x123 times)
app/models/user.rb:101:infrom_omniauth'
app/controllers/socials_controller.rb:4:in `create'
// method for signing up/logging in a user from twitter
class << self
def from_omniauth(auth_hash)
if exists?(uid: auth_hash['uid'])
user = find_by(uid: auth_hash['uid'])
else
user = find_or_create_by(uid: auth_hash['uid'], provider: auth_hash['provider'], type: 'Patient')
user.password_digest = User.digest('111111')
user.name = auth_hash['info']['name']
user.location = get_social_location_for user.provider, auth_hash['info']['location']
user.avatar = auth_hash['info']['image']
user.url = get_social_url_for user.provider, auth_hash['info']['urls']
user.save! // THIS IS THE LINE 101!
conversation = Conversation.create()
user.conversation = conversation
admin = Admin.first
admin.conversations << conversation
user.progress = Progress.create(active_state:1)
end
user
end
I think I'm messing up by using before_save not properly, but do not know how to do it right. What am I doing wrong here?
update_attribute also fires the save callbacks, thereby looping the before_save infinitely, thus producing stack level too deep.
You can just simply assign values in a before_save callback methods, because they will simply be saved afterwards anyway. See the following:
def generate_confirmation_code
unless self[:confirmed]
if(self[:type] == 'Patient')
self.confirmation_code = SecureRandom.urlsafe_base64(20)
self.confirmed = false
else
self.confirmed = true
end
end
end
You are calling update_attribute inside before_save callback method, instead you can just assign values to attributes. The method signature generate_confirmation_code should be like below -
def generate_confirmation_code
unless self[:confirmed]
if(self[:type] == 'Patient')
self.confirmation_code = SecureRandom.urlsafe_base64(20)
self.confirmed = false
else
self.confirmed = true
end
end
end

what is complex in this method

I have this action in my rails controler,
def step_submit
validate_user()
#owning = #user.create_user_car_transaction(Variant.find(params[:variant]), params[:details], params[:address], params[:somethin1])
Contact.user_contact(current_user, params[:contact]) if #user.contact.nil?
redirect_to "/next_step"
end
I use codeClimate to check the quality of the code..
it shows this action's complexity ~ 30 ..
I actually broke a really huge method into this.. how can i still reduce this complexity?
these are the different methods the action calls
def self.user_contact(user, contact_hash = nil)
contact = user.contact || user.create_contact()
contact.update_attributes(contact_hash) if contact_hash.present?
contact
end
def validate_user
if params[:user] && current_user.nil?
user = User.create(params[:user])
sign_in user
end
end
def create_user_car_transaction(car, details_hash, address_hash, coupon_hash = nil)
transaction = self.transactions.create()
car.transaction_item = transaction.transaction_items.create()
car.save
payment_hash = details_hash
payment_hash.merge!(address_hash)
payment = transaction.create_payment(payment_hash)
transaction.update_attributes(:status=>"1") if transaction.status.nil?
transaction
end

How can I work with this Module/Class setup?

I have the following module/class:
module Pigeons
class FedEx
attr_accessor :signature_name
def initialize(account)
self.account = account
end
def response(number)
body = "...some xml..."
return HTTParty.post('http://example.com', :body => body)
end
def track(number)
details = response(number)
self.signature_name = details[:delivery_signature_name]
end
end
end
What I'd like to be able to do is this:
#fedex ||= Pigeons::FedEx.new('123abc')
tracker = fedex.track('1234567890')
tracker.signature_name
Everything is working up until the tracker.signature_name part, which throws an undefined method 'signature_name' for nil:NilClass error.
The problem is in this line:
self.signature_name = details[:delivery_signature_name]
details[:delivery_signature_name] turns out to be nil, which is then assigned to self.signature_name and then becomes return value of track method. And here
tracker = fedex.track('1234567890')
tracker.signature_name
tracker will be nil and you try to call a method on it.
You probably meant to write this instead:
def track(number)
details = response(number)
self.signature_name = details[:delivery_signature_name]
self # <== here
end
You need two methods called signature_name= and response that do whatever they are supposed to do in your class.

NoMethodError in ContainerformatsController#create undefined method `yuvstreams' for #<Containerformat:0x450f560>

I am getting this error, I don't know what happened, it's been working fine few days before but it's not working now. This is the code:
#containerformat = Containerformat.new(params[:containerformat])
if #containerformat.containerFmt == 'TS'
#containerformat = Containerformat.new(params[:containerformat])
#transportstream =
#containerformat.transportstreams.build(params[:transportstream])
#transportstream.save
#program = #transportstream.programs.build(params[:program])
#program.save
#user = #containerformat.users.build(params[:user])
#user.save
if params[:videoCodec_id]!= nil
#stream = #program.streams.build(params[:stream])
#stream.videocodec = Videocodec.find(#stream.videoCodec_id)
#stream.save
end
if params[:audioCodec_id]!= nil
#stream = #program.streams.build(params[:stream])
#stream.audiocodec = Audiocodec.find(#stream.audioCodec_id)
#stream.save
end
end
if #containerformat.containerFmt == 'PS'
#programstream =
#containerformat.programstreams.build(params[:programstream])
#subtitle = #programstream.subtitles.build(params[:subtitle])
#subtitle.save
#programstream.save
#stream = #programstream.streams.build(params[:stream])
#user = #containerformat.users.build(params[:user])
#user.save
if params[:videoCodec_id]!= nil
#stream = #programstream.streams.build(params[:stream])
#stream.videocodec = Videocodec.find(#stream.videoCodec_id)
#stream.save
end
if params[:audioCodec_id]!= nil
#stream = #programstream.streams.build(params[:stream])
#stream.audiocodec = Audiocodec.find(#stream.audioCodec_id)
#stream.save
end
end
if #containerformat.containerFmt == 'YUV'
#yuvstream = #containerformat.yuvstreams.build(params[:avistream])
##subtitle = #yuvstream.subtitles.build(params[:subtitle])
##subtitle.save
#yuvstream.save
#stream = #yuvstream.streams.build(params[:stream])
#user = #containerformat.users.build(params[:user])
#user.save
if params[:videoCodec_id]!= nil
##stream = #programstream.streams.build(params[:stream])
##stream.videocodec = Videocodec.find(#stream.videoCodec_id)
##stream.save
end
if params[:audioCodec_id]!= nil
##stream = #programstream.streams.build(params[:stream])
##stream.audiocodec = Audiocodec.find(#stream.audioCodec_id)
##stream.save
end
end
if #containerformat.containerFmt == 'AVI'
#avistream = #containerformat.avistreams.build(params[:avistream])
#avistream.save
#stream = #avistream.streams.build(params[:stream])
#user = #containerformat.users.build(params[:user])
#user.save
if params[:videoCodec_id]!= nil
#stream = #avistream.streams.build(params[:stream])
#stream.videocodec = Videocodec.find(#stream.videoCodec_id)
#stream.save
end
if params[:audioCodec_id]!= nil
#stream = #avistream.streams.build(params[:stream])
#stream.audiocodec = Audiocodec.find(#stream.audioCodec_id)
#stream.save
end
end
I have yuvstreams as table in my database like other tables avisteams, programstreams table.
You need a has_many :yuvstreams in your Containerformat class.
This defines the relationship between containerformats and yuvstreams from the containerformat point of view. You can find more details in the api docs for the has_many method. Basically though, without that you can't refer to yuvstreams from a containerformat.
One additional point on style. Typically rails uses an _ and camel case to make names more readable. So you would have YuvStream and ContainerFormat as your class name and has_many :yuv_streams as your association definition. Rails expects this kind of naming and can sometimes make educated guesses about things if you use it.

Resources