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
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)