undefined local variable or method - ruby-on-rails

I am following this code https://stackoverflow.com/a/17886089/692622, here is my client.rb model file and client_controller.rb file
# app/models/client.rb
before_create :add_unsubscribe_hash
private
def add_unsubscribe_hash
self.unsubscribe_hash = SecureRandom.hex
end
# app/controllers/clients_controller.rb
def unsubscribe
client = Client.find_by_unsubscribe_hash(params[:unsubscribe_hash])
client.update_attribute(:subscription, false)
end
but when I am trying to add clients through /clients/new (I have all the 7 methods in controller file too), I am getting error
undefined local variable or method `add_unsubscribe_hash'
The error is coming while saving client in create method
respond_to do |format|
if #client.save
any idea what is wrong since everything looks alright
EDIT - I have added the model code at pastebin http://pastebin.com/jkegLsaE

Notice that in line 40 of your Pastebin, you've opened a foreach loop that should terminate on line 42, but doesn't. Instead, the foreach loop encompasses the entire add_unsubscribe_hash function declaration, so it's not callable by the :before_create callback.
Resolve this by concluding the loop within the function it should be closed in (and ensure that you remove the extraneous end tag at the end of the file):
# app/models/contact.rb
def self.import(file)
CSV.foreach(file.path, headers: true) do |row|
Contact.create! row.to_hash
end
end

Related

Adding ActiveModel Errors to ruby class

I'm trying to get Active Model Errors working in a standard ruby class that I'm using for stripe.
class Payment
attr_reader :user, :token, :errors
attr_accessor :base
extend ActiveModel::Naming
def initialize(args)
#user = args[:user]
#token = args[:stripe_token]
#errors = ActiveModel::Errors.new(self)
end
def checking_account
begin
account = Stripe::Account.retrieve(user.stripe_account_id)
account.external_account = token
account.save
rescue Stripe::StripeError => e
errors.add(:base, e.message)
end
end
# The following methods are needed to be minimally implemented
def read_attribute_for_validation(attr)
send(attr)
end
def Payment.human_attribute_name(attr, options = {})
attr
end
def Payment.lookup_ancestors
[self]
end
end
now I'm making checking_account fail on purpose by not supplying a token, and I'm just returned an array currently saying:
=> ["Invalid external_account object: must be a dictionary or a non-empty string. See API docs at https://stripe.com/docs'"]
now I've followed the steps on http://api.rubyonrails.org/classes/ActiveModel/Errors.html so I'm not sure why this isn't working, does anybody have any idea how to fix this?
when I'm calling:
Payment.new(user: User.find(1)).managed_account it triggers the array above, and if I try to call .errors on that I get
NoMethodError: undefined method `errors' for #<Array:0x007f80989d8328>
which is obviously because it's an array and the format isn't correct.
The code you have should work to fill errors. The issue is that you can't call .errors on checking_account because the return value from checking_account is an Array, not a Payment instance. You should be able to make these calls separately on the console to review:
payment = Payment.new(user: User.find(1)) # Returns Payment instance
payment.checking_account
payment.errors # Calls `errors` on Payment instance

Sidekiq: ArgumentError: When assigning attributes, you must pass a hash as an argument

I guess this question is common with Rails 4, but my situation is different.
I am using Sidekiq to delay the creation of jobs; think this is possible as with simple data, it works. By means of simple data:
def perform
Foo.create(bar: "staff")
end
Here's my data with issues:
supports_controller.rb:
def create
params = support_params // seems to be issues here?
DelayedJobs.perform_in(1.minutes, current_user.id, params)
...
end
private
def support_params
params.require(:support).permit(:foo1, :foo2, :foo3)
end
app/workers/delayed_jobs.rb:
class DelayedJobs
include Sidekiq::Worker
def perform(user_id, params)
u = User.find(user_id)
support = u.supports.build(params)
Support.create(support) // create and save to db
end
end
Via web (localhost:3000/sidekiq/scheduled, I see the details. Great. But after a minute it goes to retries with the error. Any help on this one?
EDIT:
In the sidekiq web argument:
40, {"foo1"=>"a", "foo2"=>"b", "foo3"=>"c"}
Why is that the user_id (40) is outside?
The problem isn't with Sidekiq; it's an ActiveRecord problem with this line:
Support.create(support)
create only takes a hash, but you're giving it a Support.
This should work:
class DelayedJobs
include Sidekiq::Worker
def perform(user_id, params)
u = User.find(user_id)
u.supports.create!(params) # `create!` will raise an error if the save fails; allowing you to catch invalid params
end
end
Protip: you can eliminate Sidekiq as a suspect by running the body of your perform method in a Rails console. You'll see that you get the same error even when Sidekiq isn't involved.
I suggest that you call save method on support object because when you are using build method it returns a new instance of support so you need only to save it.
class DelayedJobs
include Sidekiq::Worker
def perform(user_id, params)
u = User.find(user_id)
support = u.supports.build(params)
support.save // save to db
end
end
In your controller try to change params to:
def create
params = params[:support]

unknown attribute Rails on import CSV uninitialized constant

I am getting the error ActiveRecord::UnknownAttributeError in ProductsController#import, while trying to import a large csv file.
The migration is done and the table is created.
When i try to process the file I get,
unknown attribute 'CO_NO' for Product.
Extracted source (around line #14):
Model:
class Product < ActiveRecord::Base
attr_accessor :co_no, :parcel_id, :file_t, :asmt_yr
require 'csv'
def self.import(file)
CSV.foreach(file.path, headers: true) do |row|
product_hash = row.to_hash # exclude the price field
product = Product.where(id: product_hash["id"])
if product.count == 1
product.first.update_attributes(product_hash)
else
Product.create!(product_hash)
end # end if !product.nil?
end # end CSV.foreach
end # end self.import(file)
end # end class
controller:
classProductsController<ApplicationController
def index
#products=Product.all
end
def import
Product.import(params[:file])
redirect_toroot_url,notice:"Productsimported."
end
end
csv header:
co_no,parcel_id,file_t,asmnt_yr,bas_strt plus many more
27,"0000009500001010","R",2014
irb output:
Product.all
NameError: uninitialized constant Product
from (irb):2
from /Users/david/.rvm/rubies/ruby-2.1.3/bin/irb:11:in `<main>'
Just a hunch without trying out the code, but the error message you are showing...
unknown attribute 'CO_NO' for Product.
indicates an input attribute that is "CO_NO", but you've declared "co_no". Since Ruby is case sensitive for variable names is probably failing to find attribute "CO_NO" (as opposed to "co_no").
By adding quotes around the cvs header, I was able to get past the error.
"co_no","parcel_id","file_t","asmnt_yr","bas_strt"
Also, I discovered coming from Rails 3 to Rails 4 that attr_accessor is now handled in the controller. After these 2 tweaks the data imported correctly

Undefined local variable or method when accessing from controller to helper methods

I created a controller which called 'internal releases'.
I want to check that the multi-select objects contains at least one selection each.
In my controller I have:
class InternalReleasesController < ApplicationController
def show
if params[:run].nil?
logger.error "Attempt to get trend result without going through the internal_releases_trend_selection_url"
flash[:no_arguments] = 'You have tried accessing trend results without selecting parameters.'
redirect_to internal_releases_trend_selection_url
else
all_options = Array.new(params[:run][:category_id])
missing_selections = validate_arguments params[:run]
all_options = Array.[]params[:run][:category_id]
logger.debug "all_options is: #{all_options.class}"
end
end
end
I created a simple helper method:
module InternalReleasesHelper
def validate_arguments multiselect_hash
answer = Array.new
multiselect_arr.each do |key, val_arr|
if val_arr.length==1 # therefore, no selection made in this multiselect- the first arg will always be ""
answer << key
end
end
answer
end
end
For some reason I get:
undefined method `validate_arguments' for #<InternalReleasesController:0x007faf08bf9f78>
What might cause this?
Include helper module InternalReleasesHelper into InternalReleasesController class
class InternalReleasesController
include InternalReleasesHelper
end
Helper's method are just available into Views by default, so you should include your helper into controller:
Navigate on internal_releases_controller.rb file and insert following:
include InternalReleasesHelper

Rails - NoMethodError

I am receiving NoMethodErrors when my DeltaSynWorker runs. This happens in an application that was built as a revision of a currently working application. I am not the original programmer, and I am coming at it from a Java background (I mention this because it is possible I am missing something very obvious to others). I cannot figure out why NoMethodeError is being thrown when the code is very similar to code that is currently working fine in a different web application.
The Error:
NoMethodError: undefined method `client' for #<ApiRequestBuilder:0x0000000705a8f0>
delta_sync_worker.rb
class DeltaSyncWorker < SyncWorker
include Sidekiq::Worker
sidekiq_options queue: "delta_syncs"
def perform(subscriber_id, client_id)
sleep(10)
current_subscriber = ApiSubscriberDecorator.decorate(Subscriber.find(subscriber_id))
Time.zone = current_subscriber.time_zone
client = ApiClientDecorator.decorate(Client.find(client_id))
arb = ApiRequestBuilder.new(URI.parse(SR_HOST + '/servlet/sync/process'))
if arb.client(:subscriber => current_subscriber, :client => client)
arb.transmit
if arb.success?
current_subscriber.touch(:sync_updated_at)
decorated_client = ClientDecorator.decorate(client.model)
ConfirmationsSyncWorker.perform_in(1.hours, current_subscriber.id)
else
error_params = {:subscriber => current_subscriber.id, :response_body => arb.response.body, :request_body => arb.request.body, :sync_type => "DeltaSyncWorker"}
Airbrake.notify(:error_class => "sync_error", :error_message => "Sync Error: #{arb.response.message}", :params => error_params)
end
end
end
end
api_request_builder.rb
require 'nokogiri'
class ApiRequestBuilder < AbstractController::Base
include AbstractController::Rendering
include AbstractController::Layouts
include AbstractController::Helpers
include AbstractController::Translation
include AbstractController::AssetPaths
self.view_paths = "app/api"
attr_accessor :request_body, :request, :response, :append_request_headers, :request_method, :url
def initialize(url, *args)
#url = url
if args
args.each do |arg|
arg.each_pair{ |k,v| instance_variable_set("##{k.to_s}", v) }
end
end
end
# this will search for an api request template in api/requests, render that template and set any instance variables
def method_missing(meth, *args, &block)
if lookup_context.template_exists?("requests/#{meth.to_s}")
if args
args.each do |arg|
arg.each_pair{|k,v| instance_variable_set("##{k.to_s}", v) }
end
end
#request_body = (render :template => "requests/#{meth.to_s}")
else
super
end
end
def transmit
#request_method ||= "Post"
#request = "Net::HTTP::#{#request_method}".constantize.new(#url.path)
#request['x-ss-user'] = #subscriber.sr_user if #subscriber && #subscriber.sr_user.present?
#request['x-ss-pwd'] = #subscriber.sr_password if #subscriber && #subscriber.sr_password.present?
unless #append_request_headers.nil?
#append_request_headers.each_pair{ |k,v| #request[k] = v }
end
#request.body = #request_body if request_body? && #request.request_body_permitted?
#http = Net::HTTP.new(#url.host, #url.port)
#http.use_ssl = true
#http.verify_mode = OpenSSL::SSL::VERIFY_NONE
#response = #http.request(#request)
end
def success?
if #response.code == 200.to_s
return true
else
return false
end
end
def request_body?
unless #request_body.nil?
return true
else
return false
end
end
end
I have been looking at other NoMethodError questions here, but I cannot find an answer I feel applies to my situation. Any help is greatly appreciated. Thanks!
method_missing will catch sent messages for which there is no method defined, and the call to super at the end will pass it up to Ruby's standard method_missing behavior, which is what you are seeing (NoMethodError). However, this only happens if the if condition is not met, which is what I suspect is happening here, and would explain why it works in some situations but not in others. The call to :client, having found no matching methods along the inheritance chain, will look for a template called "requests/client" - try adding this template and see if that fixes the issue.
I know Ive seen this before and I feel like it wasn't what it appeared to be, but ya basically method missing is just intercepting the method call and when you call arb.client, it is caught by method missing and therefore tries to render api/client.xml.arb or api whatever the file type is. -- Note that there should be a file in the initializers directory named somethig like api_template_handler.rb or arb_temmplate_handler.rb, which is what allows rails to see that template type in the view directory -- make sure that is there first. Also sidenote, _client.xml.api is a partial used by the other api request in that directory (full sync),
To debug Id start by, above the following line
if lookup_context.template_exists?("requests/#{meth.to_s}")
Add a log statement
Rails.logger.debug "Can I see View?" + lookup_context.template_exists?("requests/#{meth.to_s}")
If true, then the problem is the error isnt getting caught properly because of method missing. If false, then the sidekiq worker isnt loading rails properly, or the view path isn't being added onto the rails view paths.
If true, Im guessing it might have something to do with the client model not being loaded, or an attribute on the client model not existing, that the builder is trying to call, and the error is somehow bubbling up to the api request builder class.
Oh also, just general stuff, but make sure redis and sidekiq are running, and restart passenger if its non local environment.
Let me know how it goes.

Resources