user3189916
user3189916

Reputation: 768

NoMethodError at /signup.html undefined method `each' for nil:NilClass while running Rails application

I migrated my Rails application from 3.2.13 to 4.0.0, but while running the application, I am getting the error:

Started GET "/signup.html" for 127.0.0.1 at 2016-06-29 17:28:16 +0530 ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations".* FROM "schema_migrations" Processing by AccountsController#new as HTML Parameters: {"plan"=>"year"} Completed 500 Internal Server Error in 51ms ** [Airbrake] Notice was not sent due to configuration: Environment Monitored? false API key set? true

NoMethodError - undefined method each' for nil:NilClass:
activemerchant (1.47.0) lib/active_merchant/billing/model.rb:11:in
initialize' app/controllers/accounts_controller.rb:83:in load_billing' activesupport (4.0.0) lib/active_support/callbacks.rb:437:in _run__3203841093432473566__process_action__callbacks' activesupport (4.0.0) lib/active_support/callbacks.rb:80:in run_callbacks'
actionpack (4.0.0) lib/abstract_controller/callbacks.rb:17:in
process_action' actionpack (4.0.0) lib/action_controller/metal/rescue.rb:29:in `process_action'
.......................................

This is my controller code :

class AccountsController < ApplicationController

  #inherit_resources
  ssl_required :new, :create
  before_filter :load_billing, :only => [:new, :create]

  def new
    @account_name = Rails.application.config.custom.accounts.send(params[:account_name]).name
    @account_signup_message = Rails.application.config.custom.accounts.send(params[:account_name]).signup_message
  rescue
    nil
  end

  def create
    @address.first_name = @creditcard.first_name
    @address.last_name = @creditcard.last_name
    @account.address = @address
    @account.creditcard = @creditcard

    if @account.new_record?
      if @account.save
        flash[:notice] = 'Account was created.'
        sign_in(@user, :bypass => true)
        redirect_to session[:previous_url] || user_reports_path(@user)
      else
        render :action => 'new'
      end
    else
      @user.account_id = @account.id
      if @user.save
        flash[:notice] = 'User was created.'
        sign_in(@user, :bypass => true)
        redirect_to session[:previous_url] || user_reports_path(@user)
      else
        render :action => 'new'
      end
    end
  end

  protected

  def load_billing
    @creditcard = ActiveMerchant::Billing::CreditCard.new(params[:account].blank? ? nil : params[:account][:creditcard]) #This is the line it is showing error.
    @address = SubscriptionAddress.new(params[:account].blank? ? nil : params[:account][:address])
  end

end

routes.rb:

get '/signup'   => 'accounts#new'

accounts/new.html.erb:

<%= semantic_form_for(@account, :url => account_create_path, :html => { :multipart => true, :class => 'billing'}) do |f| %>

  <%= f.inputs :for => :user do |u| %>
     #name and email fields are mentioned.
  <% end %>

  <%= f.inputs :for => :creditcard do |c| %>
     #name, card_no, cvv, expire_date etc;
  <% end %>
<% end %>

This is my activemerchant (1.47.0) lib/active_merchant/billing/model.rb:

require "active_merchant/billing/compatibility"
require "active_merchant/empty"

module ActiveMerchant
  module Billing
    class Model
      include Compatibility::Model
      include Empty

      def initialize(attributes = {})
        attributes.each do |key, value|
          send("#{key}=", value)
        end
      end

      def validate
        {}
      end

      private

      def errors_hash(array)
        array.inject({}) do |hash, (attribute, error)|
          (hash[attribute] ||= []) << error
          hash
        end
      end
    end
  end
end

include Empty is the error showing line in the above code. And there is no model.rb file for activemerchant version 1.20.4 (my previous). Please help me.

Upvotes: 1

Views: 227

Answers (3)

ruby_newbie
ruby_newbie

Reputation: 3275

"include Empty is the error showing line in the above code. " No it is raising an exception on line 11 which is " attributes.each do |key, value|" because attributes is nil.

So change this line:

@creditcard = ActiveMerchant::Billing::CreditCard.new(params[:account].blank? ? nil : params[:account][:creditcard])

to this:

@creditcard = ActiveMerchant::Billing::CreditCard.new(params[:account].blank? ? {} : params[:account][:creditcard])

now you will be sending through something that won't raise if you call .each on it.

foo = {}
 => {} 
2.3.0 :002 > foo.each {|key, value| puts "#{key}=#{value}" }
 => {} 

But just so that you understand:

In the initialize method this line

def initialize(attributes = {})

initializes an instance of the class with a default parameter of an empty hash if no other parameter is being passed in. In your ternary on this line:

@creditcard = ActiveMerchant::Billing::CreditCard.new(params[:account].blank? ? nil : params[:account][:creditcard]) 

this:

params[:account].blank? ? nil : params[:account][:creditcard]

says that if there are no account params, send nil as a parameter to initialize. The nil value overwrites the default({}) value and you get undefined method each on nil class because you are calling:

attributes.each do |key, value|

but you have defined attributes as nil.

Upvotes: 2

Prasad Surase
Prasad Surase

Reputation: 6574

ActiveMerchant.new requires an hash of attributes and their values(default is empty hash), but you are passing nil which is causing the error. Check this implementation for better understanding. I think that you need not pass anything(not even nil) if params[:account][:creditcard] is not present.

Upvotes: 1

Bozidar Milivojevic
Bozidar Milivojevic

Reputation: 109

You forgot to close square brackets on before_action call.

Upvotes: 0

Related Questions