How to update the users balance when a user makes a transaction?

I am stock trying to write the code that make possible for users to update a balance every time they make a transaction.

This is a simple bartering application: The user can either offer products for sale or buy products from other users. The user pays with a kind of virtual money (units). When a user clicks in Order a transaction is executed.

The Models are: User, Product and Order.

If the user orders a product ( here order=transaction) I expect that the orders price (here price=amount) will be added to the users balance:

My expectation is that this code in orders_controller could make that the amount of @price pass and adds to @balance and makes possible the update:

@user.balance = balance: (@user.balance += @order.price) 

But this is not working

I have tried as well in orders_controller with this:

def balance
    if @order.save
@user.balance_update!(balance: @user.balance + @order.price)
end
end

But doesnt work.

What could be wrong with this code? Please help!

These are the relevant files:

class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable

validates :fullname,presence: true
validates :description, presence: false
validates :balance, presence: true, numericality:true

before_validation :load_defaults

def load_defaults
if self.new_record?
self.balance = 100
end
end
has_many :products
has_many :orders
end

class Order < ActiveRecord::Base
belongs_to :user
belongs_to :product


validates :price, presence: true
validates :product_id, presence: true
validates :user, presence: true
end

class Product < ActiveRecord::Base
belongs_to :user
has_many :orders
end

class OrdersController < ApplicationController

before_action :authenticate_user!

def create
@order = current_user.orders.create(order_params)
@user.balance = balance: (@user.balance += @order.price)

redirect_to user_orders_path
end
end

def user_orders
@orders = current_user.orders
end

private
def order_params
params.require(:order).permit(:price, :user_id)
end
end

class UsersController < ApplicationController

def show
@user = User.find(params[:id])
@products = @user.products
end
end

class ProductsController < ApplicationController
before_action :set_product, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:show]
def index
@products = current_user.products
end

def show
end

def new
@product = current_user.products.build
end
def edit
end

def create
@product = current_user.products.build(product_params)

respond_to do |format|
if @product.save
format.html { redirect_to @product, notice: 'Product was successfully created.' }
format.json { render :show, status: :created, location: @product }
else
format.html { render :new }
format.json { render json: @product.errors, status: :unprocessable_entity }
end
end
end

def update
respond_to do |format|
if @product.update(product_params)
format.html { redirect_to @product, notice: 'Product was successfully updated.' }
format.json { render :show, status: :ok, location: @product }
else
format.html { render :edit }
format.json { render json: @product.errors, status: :unprocessable_entity }
end
end
end

def destroy
@product.destroy
respond_to do |format|
format.html { redirect_to products_url, notice: 'Product was successfully destroyed.' }
format.json { head :no_content }
end
end

private
def set_product
@product = Product.find(params[:id])
end

def product_params
params.require(:product).permit(:name, :description, :price)
end
end

<p>
User name: <%= @user.fullname %>
</p>
<p>
Balance: <%= @user.balance %>
</p>

ActiveRecord::Schema.define(version: 20171031150052) do
create_table "orders", force: :cascade do |t|
t.integer "user_id"
t.integer "product_id"
t.integer "price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "transactiontype"
t.integer "buyer_id"
t.integer "seller_id"
end
add_index "orders", ["product_id"], name: "index_orders_on_product_id"
add_index "orders", ["user_id"], name: "index_orders_on_user_id"

create_table "products", force: :cascade do |t|
t.string "name"
t.text "description"
t.integer "price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
end
add_index "products", ["user_id"], name: "index_products_on_user_id"

create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "fullname"
t.string "description"
t.integer "balance"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end

Rails.application.routes.draw do
  devise_for :users

 get 'pages/index'

  resources :products
  resources :users

  resources :products do
  resources :orders, only: [:create]
  end
 
 resources :orders, only: [:show]
get '/user_orders' => 'orders#user_orders'
end

2 answers

  • answered 2017-11-12 19:56 Aakash Gupta

    Try @user.update(balance: @user.balance + @order.price)

  • answered 2017-11-12 20:30 spickermann

    If you assign an attribute directly you just assign a value and need call save yourself:

    @user.balance = @order.price
    @user.save!
    

    Or you can use update (there is no balance_update), then you call it with a hash:

    @user.update!(balance: @user.balance + @order.price)