Not able to validate credit card using active merchant? - ruby-on-rails

When i charge credit card using form, it throws validation error "The credit card information you provided is not valid. Please double check the information you provided and then try again."
Any solution??
This is my payment.rb
class Payment < ActiveRecord::Base
require "active_merchant/billing/rails"
attr_accessor :card_security_code
attr_accessor :credit_card_number
attr_accessor :expiration_month
attr_accessor :expiration_year
validates :first_name, presence: true
validates :last_name, presence: true
validates :card_security_code, presence: true
validates :credit_card_number, presence: true
validates :expiration_month, presence: true, numericality: { greater_than_or_equal_to: 1, less_than_or_equal_to: 12 }
validates :expiration_year, presence: true
validates :amount, presence: true, numericality: { greater_than: 0 }
validate :valid_card
def credit_card
ActiveMerchant::Billing::CreditCard.new(
number: credit_card_number,
verification_value: card_security_code,
month: expiration_month,
year: expiration_year,
first_name: first_name,
last_name: last_name
)
end
def valid_card
if !credit_card.valid?
errors.add(:base, "The credit card information you provided is not valid. Please double check the information you provided and then try again.")
false
else
true
end
end
def process
if valid_card
response = GATEWAY.authorize(amount * 100, credit_card)
if response.success?
transaction = GATEWAY.capture(amount * 100, response.authorization)
if !transaction.success?
errors.add(:base, "The credit card you provided was declined. Please double check your information and try again.") and return
false
end
update_columns({authorization_code: transaction.authorization, success: true})
true
else
errors.add(:base, "The credit card you provided was declined. Please double check your information and try again.") and return
false
end
end
end
end
This is my activemerchant.rb
if Rails.env == 'development'
ActiveMerchant::Billing::FirstdataE4Gateway.wiredump_device = File.open(Rails.root.join('log','active_merchant.log'), 'a+')
ActiveMerchant::Billing::FirstdataE4Gateway.wiredump_device.sync = true
ActiveMerchant::Billing::Base.mode = :test
login = 'mylogin'
password='mypassword'
elsif Rails.env == 'production'
login = 'mylogin'
password='mypassword'
end
GATEWAY = ActiveMerchant::Billing::FirstdataE4Gateway.new({
login: login,
password: password
})
Check here

You also need to provide credit card brand name as
def credit_card
ActiveMerchant::Billing::CreditCard.new(
number: credit_card_number, # 4111111111111111
verification_value: card_security_code, # 123
month: expiration_month, # 1
year: expiration_year, # 2020
first_name: first_name, # Bibek
last_name: last_name, # Sharma
brand: credit_card_brand # visa
)
end

Related

Can you help me understand why this boolean method is returning false?

I have a User model with an account_type attribute that is either "Student" or "Partner". I have created boolean methods in my User model to determine if a user record is either a student or partner (see below).
def student?
self.account_type == "Student"
end
def partner?
self.account_type == "Partner"
end
In rails console, when I set user equal to an instance of User that has a student account type and enter user.account_type == "Student", I get true but when I call user.student?, I get false. Is there an issue with how I've set up these methods? They seem pretty straight forward so I'm not following why true isn't returned for the record.
Console Output:
user = User.last
#<User id: 18, first_name: "gjalrgkj", last_name: "kgjrlgakjrl", email: "terajglrkj#gmail.com", password_digest: "$2a$10$WF.Rw3PzlWilH0X.Nbfxfe5aB18WW6J7Rt4SAKQEwI8...", remember_digest: nil, activation_digest: "$2a$10$/bXG4/nKCiiZHWailUPAmOZj7YhCjKhPm4lUW6nPC3N...", activated: nil, activated_at: nil, reset_digest: nil, reset_sent_at: nil, account_type: "Student", created_at: "2018-07-02 04:21:07", updated_at: "2018-07-02 04:21:07">
>> user.account_type
=> "Student"
>> user.account_type = "Student"
=> "Student"
>> user.student?
=> false
User Model:
class User < ApplicationRecord
has_one :personal_information
attr_accessor :remember_token, :activation_token, :reset_token
before_save :downcase_email
before_create :create_activation_digest
validates :first_name, presence: true, length: { maximum: 50 }
validates :last_name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
has_secure_password
validates :password, presence: true, length: { minimum: 6 }, allow_nil: true
validates :account_type, presence: true
def User.new_token
SecureRandom.urlsafe_base64
end
def User.digest(string)
cost = ActiveModel::SecurePassword.min_cost BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
def create_reset_digest
self.reset_token = User.new_token
update_columns(reset_digest: User.digest(reset_token), reset_sent_at: Time.zone.now)
end
def authenticated?(attribute, token)
return false if digest.nil?
BCrypt::Password.new(digest).is_password?(token)
end
def remember
self.remember_token = User.new_token
update_attribute(:remember_digest, User.digest(remember_token))
end
def forget
update_attribute(:remember_digest, nil)
end
def provide_age
now = Time.now.utc.to_date
if self.birthday.nil?
nil
else
self.age = now.year - self.birthday.year - ((now.month > self.birthday.month || (now.month == self.birthday.month && now.day >= self.birthday.day)) ? 0 : 1)
update_attribute(:age, self.age)
end
end
def send_activation_email
UserMailer.account_activation(self).deliver_now
end
def activate
update_columns(activated: true, activated_at: Time.zone.now)
end
def send_password_reset_email
UserMailer.password_reset(self).deliver_now
end
def password_reset_expired?
reset_sent_at < 2.hours.ago
end
private
def downcase_email
self.email.downcase!
end
def create_activation_digest
self.activation_token = User.new_token
self.activation_digest = User.digest(activation_token)
end
end
User Helper
def account_type
[
['Student'],
['Partner'],
['School Administrator'],
['Philanthropist']
]
end
def student?
self.account_type == "Student"
end
def partner?
self.account_type == "Partner"
end
end
Your 2 methods student? and partner? belong in the user model.
When you are doing user.student? it looks for student? method as a instance method in the user model.
self in helper is not the user instance it points to your helper module.
Hope this helps.
try to put this code into your User Model (not in Helper)
def student?
self.account_type == "Student"
end
def partner?
self.account_type == "Partner"
end
and this is a good idea to create a setter to set the account_type, example
def set_account_type(type)
self.account_type = type
end

Rails unit test failing

The following User test passes with no problem, the user is valid:
user_test.rb:
require 'test_helper'
class UserTest < ActiveSupport::TestCase
def setup
#user = User.new(name: "Example User", email: "user#example.com", callsign: "example",
password: "foobar", password_confirmation: "foobar")
end
test "user should be valid" do
assert #user.valid?
end
end
User model:
class User < ActiveRecord::Base
attr_accessor :remember_token, :activation_token, :reset_token
has_many :personas, dependent: :destroy
has_secure_password
before_save do
email.downcase!
callsign.downcase!
end
before_create :create_activation_digest
validates :name, presence: true,
length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(?:\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true,
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
VALID_CALLSIGN_REGEX = /\A[a-z\d\-.\_]+\z/i
validates :callsign, presence: true,
length: { maximum: 20 },
format: { with: VALID_CALLSIGN_REGEX },
uniqueness: { case_sensitive: false }
validates :password, length: { minimum: 6 }, allow_blank: true
def to_param
callsign
end
.
.
end
However, when I set up exactly the same user in the persona_test, the validation fails. (The persona validation fails too, each User has_many personas)
persona_test.rb:
require 'test_helper'
class PersonaTest < ActiveSupport::TestCase
def setup
#user = User.new(name: "Example User", email: "user#example.com", callsign: "example",
password: "foobar", password_confirmation: "foobar")
#persona = #user.personas.build(name: "Bazman", callsign: "Baz")
end
test "user should be valid" do
assert #user.valid?
end
test "persona should be valid" do
assert #persona.valid?
end
end
Persona model:
class Persona < ActiveRecord::Base
belongs_to :user
before_save do
self.callsign.downcase!
set_persona_id
end
validates :name, presence: true,
length: { maximum: 50 }
VALID_CALLSIGN_REGEX = /\A[a-z\d\-.\_]+\z/i
validates :callsign, presence: true,
length: { maximum: 20 },
format: { with: VALID_CALLSIGN_REGEX },
uniqueness: { case_sensitive: false }
validates :user_id, presence: true
validates :persona_id, presence: true
def to_param
callsign
end
.
.
end
Failed test output:
FAIL["test_user_should_be_valid", PersonaTest, 0.754914]
test_user_should_be_valid#PersonaTest (0.75s)
Failed assertion, no message given.
test/models/persona_test.rb:18:in `block in <class:PersonaTest>'
FAIL["test_persona_should_be_valid", PersonaTest, 0.893247]
test_persona_should_be_valid#PersonaTest (0.89s)
Failed assertion, no message given.
test/models/persona_test.rb:22:in `block in <class:PersonaTest>'
I don't understand why the User validation in persona_test.rb is failing when the setup user is identical to the one in user_test.rb. Are you not allowed to test Users in a Personas test? If so, how do I successfully test personas? Each persona belongs_to a user, so I have to create a user in order to create a persona.
EDIT:
persona_test.rb:
require 'test_helper'
class PersonaTest < ActiveSupport::TestCase
def setup
#user = User.new(name: "Example User", email: "user#example.com", callsign: "example",
password: "foobar", password_confirmation: "foobar")#, activated: true)
#persona = #user.personas.build(name: "Bazman", callsign: "Baz")
#persona.user = #user
#persona.persona_id = 1
end
test "user should be valid" do
assert #user.valid?, #user.errors.full_messages
end
test "persona should be valid" do
assert #persona.valid?, #persona.errors.full_messages
end
end
With the updated persona test above, I get the error message 'User can't be blank'. Why is
#persona.user = #user
not working?
The reason for the failed assertion is that some validations in Persona won't pass:
validates :user_id, presence: true
validates :persona_id, presence: true
The validations are run before saving them to the database. For new records, user_id and persona_id will still be nil.
Because Persona is invalid, the User will be invalid in the other test as well.
In your persona model you have:
validates :user_id, presence: true
validates :persona_id, presence: true
But it doesn't look like a user_id is being set. Try setting it with #persona.user = #user in your test.
Additionally, as a tool for debugging, you can print #persona.errors.full_messages in your test to see where exactly it is not validating.
E.g. assert #persona.valid?, #persona.errors.full_messages
Hope that helps.
EDIT: as per the comments below, the line should actually be #persona.user_id = #user.id. Another way you could achieve the same effect is to actually save the records to the database. So in your setup function, you would use create instead of build. This would, however, be slower.

How to set a virtual attribute in model with Rails?

I have a model User with usual attributes email, email_confirmation, password, password_confirmation. I use "has_secure_password" so the real attributes in the database are email and password_digest. However I would like to limit password length without spaces to 6 characters.
Here is my model :
class User < ActiveRecord::Base
before_validation :auto_strip_confirmation
validates :email, presence: true,
length: { maximum: MAX_SIZE_DEFAULT_INPUT_TEXT },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false },
confirmation: true
validates :email_confirmation, presence: true
has_secure_password
validates :password, length: { minimum: MIN_SIZE_USER_PASSWORD,
maximum: MAX_SIZE_USER_PASSWORD }
private
def auto_strip_confirmation
self.password.strip!
self.password_confirmation.strip!
end
end
But I get this in console :
> user.password = user.password_confirmation = "a "
=> "a "
> user.valid?
User Exists (0.8ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('user#example.com') LIMIT 1
=> true
Thanks for your help.
After reload, my code actually works in console : user.valid? => false (thanks surendran). But my initial problem was in my tests : I thought I could not set virtual attributes because of the error message "undefined method `strip!' for nil:NilClass". But I forgot I test if my user is valid when password is nil, nearly like this :
before { user.password = nil) }
it { should_not be_valid }
before_validation comes before this test so he tries to strip a nil object.

Hide password_digest error message in JSON output

I'm building a simple JSON API using the rails-api gem.
models/user.rb:
class User < ActiveRecord::Base
has_secure_password
attr_accessible :email, :password, :password_confirmation
validates :email, presence: true, uniqueness: { case_sensitive: false }, format: { with: /^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i }
validates :password, presence: { on: :create }, length: { minimum: 6 }
end
When I try to sign up without a password this is the JSON output I get:
{
"errors": {
"password_digest": [
"can't be blank"
],
"password": [
"can't be blank",
"is too short (minimum is 6 characters)"
]
}
}
Is it possible to hide the error message for password_digest? I'm returning the #user object with respond_with in the controller.
I've tried the following but no luck (it just duplicates the error "can't be blank"):
validates :password_digest, presence: false
#freemanoid: I tried your code, and it didn't work. But it gave me some hints. Thanks! This is what worked for me:
models/user.rb
after_validation { self.errors.messages.delete(:password_digest) }
You can manually delete this message in json handler in User model. Smth like:
class User < ActiveRecord::Base
def as_json(options = {})
self.errors.messages.delete('password_digest')
super(options)
end
end

NoMethodError: undefined method `*' for nil:NilClass Factory Girl/Capybara issue

This particular test is trying to create a 'status update' for a user.
Here is the full error:
Failure/Error: FactoryGirl.create(:status_update, user: #user, created_at: 1.day.ago)
NoMethodError:
undefined method `*' for nil:NilClass
# ./app/models/status_update.rb:31:in `default_values'
# ./spec/models/user_spec.rb:28:in `block (3 levels) in <top (required)>'
Here is the test:
describe "Status Update Associations" do
before { #user.save }
let!(:older_status_update) do
FactoryGirl.create(:status_update, user: #user, created_at: 1.day.ago)
end
let!(:newer_status_update) do
FactoryGirl.create(:status_update, user: #user, created_at: 1.hour.ago )
end
it "should have status updates in the right order" do
#user.status_update.should == [newer_status_update, older_status_update]
end
end
Since the error is pointing to the status update model I might as well include that here as well. I suspect it's got something to do with some variables being set after initialization and the let! in the test, although I'm stumped with trying different callbacks.
class StatusUpdate < ActiveRecord::Base
belongs_to :user
after_initialize :default_values
attr_accessible :current_weight,
:current_bf_pct,
:current_lbm,
:current_fat_weight,
:change_in_weight,
:change_in_bf_pct,
:change_in_lbm,
:change_in_fat_weight,
:total_weight_change,
:total_bf_pct_change,
:total_lbm_change,
:total_fat_change
validates :user_id, presence: true
validates :current_bf_pct, presence: true,
numericality: true,
length: { minimum: 4, maximum:5 }
validates :current_weight, presence: true,
numericality: true,
length: { minimum: 4, maximum:5 }
validates :current_lbm, presence: true
validates :current_fat_weight, presence: true
def default_values
self.current_fat_weight = self.current_weight * self.current_bf_pct
self.current_lbm = self.current_weight - self.current_fat_weight
end
default_scope order: 'status_update.created_at DESC'
end
Here is the factory that adds the 'current_weight and current_bf_pct to the default_values method.
factory :status_update do
user
current_weight 150
current_bf_pct 0.15
end
Thanks!
It's due to your default_values method.
You're doing self.current_weight * self.current_bf_pct but none of them are set to a numerical value.

Resources