I can't seem to figure out why my PartTransactions test keep failing for updating and creating. All of my other test are successful so, to me I feel like I'm maybe doing something incorrectly in my fixtures - any suggestions would be greatly appreciated!
Here are the failure results when I run my test
Running via Spring preloader in process 62590
Started with run options --seed 23873
FAIL["test_should_create_part_transaction", #<Minitest::Reporters::Suite:0x00007f96615c1710 #name="PartTransactionsControllerTest">, 0.644004000001587]
test_should_create_part_transaction#PartTransactionsControllerTest (0.64s)
"PartTransaction.count" didn't change by 1.
Expected: 3
Actual: 2
test/controllers/part_transactions_controller_test.rb:19:in `block in <class:PartTransactionsControllerTest>'
FAIL["test_should_update_part_transaction", #<Minitest::Reporters::Suite:0x00007f966163a548 #name="PartTransactionsControllerTest">, 0.6869309999747202]
test_should_update_part_transaction#PartTransactionsControllerTest (0.69s)
Expected response to be a <3XX: redirect>, but was a <200: OK>
test/controllers/part_transactions_controller_test.rb:38:in `block in <class:PartTransactionsControllerTest>'
21/21: [===========================================================================================================================================================================================================================================] 100% Time: 00:00:00, Time: 00:00:00
Finished in 0.77788s
21 tests, 26 assertions, 2 failures, 0 errors, 0 skips
Here is my schema.rb
ActiveRecord::Schema.define(version: 2019_01_30_150153) do
create_table "customers", force: :cascade do |t|
t.string "cust_id"
t.string "cust_name"
t.integer "cust_status"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "part_transactions", force: :cascade do |t|
t.integer "trans_id"
t.datetime "trans_date"
t.decimal "trans_qty", precision: 14, scale: 4
t.string "trans_type"
t.string "invoiced"
t.decimal "cs_trans_qty", precision: 6, scale: 2
t.integer "part_id"
t.integer "customer_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["customer_id"], name: "index_csi_part_transactions_on_customer_id"
t.index ["part_id"], name: "index_csi_part_transactions_on_part_id"
end
create_table "parts", force: :cascade do |t|
t.string "part_id"
t.string "description"
t.decimal "qty_on_hand", precision: 14, scale: 4
t.decimal "order_point", precision: 14, scale: 4
t.decimal "reorder_qty", precision: 14, scale: 4
t.string "part_type"
t.string "status"
t.string "inv_cs"
t.decimal "cs_qty", precision: 3
t.string "cs_status"
t.integer "customer_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["customer_id"], name: "index_csi_parts_on_customer_id"
end
end
Here are my models
class Customer < ApplicationRecord
has_many :parts, :dependent => :destroy
has_many :part_transactions, :dependent => :destroy
end
class Part < ApplicationRecord
belongs_to :customer
has_many :part_transactions, :dependent => :destroy
end
class PartTransaction < ApplicationRecord
belongs_to :part
belongs_to :customer
end
Here are my fixtures
#Customer -------------------------------------------------------------
one:
cust_id: one
cust_name: My Company
cust_status: 3
two:
cust_id: two
cust_name: Other Company
cust_status: 1
#Parts-------------------------------------------------------------
one:
part_id: one
description: TestA
qty_on_hand: 2
order_point: 3
reorder_qty: 1
part_type: TestAPartType
status: F
inv_cs: 2
cs_qty: 3
cs_status: F
customer: one
two:
part_id: two
description: TestB
qty_on_hand: 1
order_point: 3
reorder_qty: 6
part_type: TestBPartType
status: F
inv_cs: 2
cs_qty: 3
cs_status: C
customer: two
#PartTransactions------------------------------------------------------
one:
trans_id: one
trans_date: 2019-01-31
trans_qty: 1
trans_qty: 1
trans_type: 1
invoiced: 1
cs_trans_qty: 1
cs_trans_qty: 1
part_id: one
customer: one
two:
trans_id: 2
trans_date: 2019-01-31
trans_qty: 3
trans_qty: 3
trans_type: 3
invoiced: 1
cs_trans_qty: 1
cs_trans_qty: 1
part_id: two
customer: two
Here is my PartTransaction Test
require 'test_helper'
class PartTransactionsControllerTest < ActionDispatch::IntegrationTest
setup do
#part_transaction = part_transactions(:one)
end
test "should get index" do
get part_transactions_url
assert_response :success
end
test "should get new" do
get new_part_transaction_url
assert_response :success
end
test "should create part_transaction" do
assert_difference('PartTransaction.count') do
post part_transactions_url, params: { part_transaction: { cs_trans_qty: #part_transaction.cs_trans_qty, customer_id: #part_transaction.customer_id, invoiced: #part_transaction.invoiced, part_id: #part_transaction.part_id, trans_date: #part_transaction.trans_date, trans_id: #part_transaction.trans_id, trans_qty: #part_transaction.trans_qty, trans_type: #part_transaction.trans_type } }
end
assert_redirected_to part_transaction_url(PartTransaction.last)
end
test "should show part_transaction" do
get part_transaction_url(#part_transaction)
assert_response :success
end
test "should get edit" do
get edit_part_transaction_url(#part_transaction)
assert_response :success
end
test "should update part_transaction" do
patch part_transaction_url(#part_transaction), params: { part_transaction: { cs_trans_qty: #part_transaction.cs_trans_qty, customer_id: #part_transaction.customer_id, invoiced: #part_transaction.invoiced, part_id: #part_transaction.part_id, trans_date: #part_transaction.trans_date, trans_id: #part_transaction.trans_id, trans_qty: #part_transaction.trans_qty, trans_type: #part_transaction.trans_type } }
assert_redirected_to part_transaction_url(#part_transaction)
end
test "should destroy part_transaction" do
assert_difference('PartTransaction.count', -1) do
delete part_transaction_url(#part_transaction)
end
assert_redirected_to part_transactions_url
end
end
Here is my PartTransactionsController
class PartTransactionsController < ApplicationController
before_action :set_part_transaction, only: [:show, :edit, :update, :destroy]
# GET /part_transactions
# GET /part_transactions.json
def index
#part_transactions = PartTransaction.all
end
# GET /part_transactions/1
# GET /part_transactions/1.json
def show
end
# GET /part_transactions/new
def new
#part_transaction = PartTransaction.new
end
# GET /part_transactions/1/edit
def edit
end
# POST /part_transactions
# POST /part_transactions.json
def create
#part_transaction = PartTransaction.new(part_transaction_params)
respond_to do |format|
if #part_transaction.save
format.html { redirect_to #part_transaction, notice: 'Part transaction was successfully created.' }
format.json { render :show, status: :created, location: #part_transaction }
else
format.html { render :new }
format.json { render json: #part_transaction.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /part_transactions/1
# PATCH/PUT /part_transactions/1.json
def update
respond_to do |format|
if #part_transaction.update(part_transaction_params)
format.html { redirect_to #part_transaction, notice: 'Part transaction was successfully updated.' }
format.json { render :show, status: :ok, location: #part_transaction }
else
format.html { render :edit }
format.json { render json: #part_transaction.errors, status: :unprocessable_entity }
end
end
end
# DELETE /part_transactions/1
# DELETE /part_transactions/1.json
def destroy
#part_transaction.destroy
respond_to do |format|
format.html { redirect_to part_transactions_url, notice: 'Part transaction was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_part_transaction
#part_transaction = PartTransaction.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def part_transaction_params
params.require(:part_transaction).permit(:trans_id, :trans_date, :trans_qty, :trans_qty, :trans_type, :invoiced, :cs_trans_qty, :cs_trans_qty, :part_id, :customer_id)
end
end
I don't know how I missed this but, I figured it out and it was caused by my part_transactions fixture - see below
I had part_id in my fixture when it should of been part (*smacks self on the head)
one:
trans_id: one
trans_date: 2019-01-31
trans_qty: 1
trans_qty: 1
trans_type: 1
invoiced: 1
cs_trans_qty: 1
cs_trans_qty: 1
#should be part not part_id
#part_id: one
part: one
customer: one
two:
trans_id: 2
trans_date: 2019-01-31
trans_qty: 3
trans_qty: 3
trans_type: 3
invoiced: 1
cs_trans_qty: 1
cs_trans_qty: 1
#should be part not part_id
#part_id: two
part: two
customer: two
I am using RSpec to test my controller actions and have been successfully tested my index, show, edit actions so far. But for create action it is giving me the following error for valid attributes. I'm using rails 5 and ruby 2.5.3. Can't understand what am I doing wrong.
file /spec/factories/leaves.rb
FactoryBot.define do
factory :leave do
id {Faker::Number.between(from = 1, to = 3)}
user_id {Faker::Number.between(from = 1, to = 3)}
team_lead_id {Faker::Number.between(from = 1, to = 3)}
fiscal_year_id {Faker::Number.between(from = 1, to = 3)}
start_day {Date.today - Faker::Number.number(3).to_i.days}
end_day {Date.today - Faker::Number.number(3).to_i.days}
reason {Faker::Lorem.sentences(sentence_count = 3, supplemental = false)}
status {Faker::Number.between(from = 1, to = 3)}
factory :invalid_leave do
user_id nil
end
end
end
file /spec/controllers/leave_controller_spec.rb
context 'with valid attributes' do
it 'saves the new leave in the database' do
leave_params = FactoryBot.attributes_for(:leave)
expect{ post :create, params: {leave: leave_params}}.to change(Leave,:count).by(1)
end
it 'redirects to leave#index' do
render_template :index
end
end
file /app/controller/leave_controller.rb
def create
#leave = Leave.new(leave_params)
if #leave.save
flash[:notice] = t('leave.leave_create')
redirect_to leave_index_path
else
flash[:notice] = t('leave.leave_create_error')
redirect_to leave_index_path
end
end
The error is:
LeaveController POST#create with valid attributes saves the new leave in the database
Failure/Error: expect{ post :create, params: {leave: leave_params}}.to change(Leave,:count).by(1)
expected `Leave.count` to have changed by 1, but was changed by 0
# ./spec/controllers/leave_controller_spec.rb:64:in `block (4 levels) in <top (required)>'
Update Leave Database
create_table "leaves", force: :cascade do |t|
t.integer "user_id", null: false
t.integer "team_lead_id", null: false
t.integer "fiscal_year_id", null: false
t.date "start_day", null: false
t.date "end_day", null: false
t.text "reason", null: false
t.integer "status", null: false
t.string "comment"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Leave Model
class Leave < ApplicationRecord
validates :user_id, :team_lead_id, :fiscal_year_id, :start_day, :end_day, :reason, :status, presence: true
end
I think that might be because of id which you set in factory. You shouldn't set id attribute in factory. That's why number of Leave objects didn't change.
Additionally, I assume that you have some relations there - user_id, team_lead_id etc. If these relations are necessarry to create leave object then you have to create factories for these models, too.
In the end your factory should look like this
FactoryBot.define do
factory :leave do
user
team_lead
fiscal_year
start_day {Date.today - Faker::Number.number(3).to_i.days}
end_day {Date.today - Faker::Number.number(3).to_i.days}
reason {Faker::Lorem.sentences(sentence_count = 3, supplemental = false)}
status {Faker::Number.between(from = 1, to = 3)}
factory :invalid_leave do
user nil
end
end
end
Reference: Factory Bot documentation - associations
[For Future Reader] I got it to work by doing the fooling in leave_controller_spec.rb file.
describe 'POST#create' do
context 'with valid attributes' do
let(:valid_attribute) do
attributes_for(:leave,
user_id: 2,
team_lead_id: 3,
fiscal_year_id: 2,
start_day: '2018-10-10'.to_date,
end_day: '2018-10-10'.to_date,
reason: 'Sick',
status: 2)
end
it 'saves the new leave in the database' do
expect do
post :create, params: {leave: valid_attribute}
end.to change(Leave,:count).by(1)
end
it 'redirects to leave#index' do
render_template :index
end
end
Location is basically an address with other information fields. This is my first app and I followed Hartl and others in building it, but ignored failing tests that I couldn't fix at the time. Now I'm trying to rectify that. I've looked at all the postings I found with this problem, but still can't figure it out (discussed at end). The app works, I can create new locations, so I think the error is with the test.
FAIL["test_should_create_location", LocationsControllerTest, 2017-02-28 12:02:08 -0800]
test_should_create_location#LocationsControllerTest (1488312128.31s)
"Location.count" didn't change by 1.
Expected: 4
Actual: 3
test/controllers/locations_controller_test.rb:21:in `block in <class:LocationsControllerTest>'
Edited location_controller_test.rb (The location controller test has 8 tests, this is the one that fails):
require 'test_helper'
class LocationsControllerTest < ActionController::TestCase
setup do
#location = locations(:one)
end
test "should create location" do
assert_difference('Location.count') do
post :create, location: { address: #location.address,
city: #location.city,
state: #location.state,
longitude: #location.longitude,
latitude: #location.latitude,
geom: #location.geom,
coords_not_locked: #location.coords_not_locked,
geocoded_with: #location.geocoded_with,
extant: #location.extant,
current_description: #location.current_description,
source: #location.source,
ref_link: #location.ref_link,
notes: #location.notes }
# debugger
end
assert_redirected_to location_path(assigns(:location))
end
locations_controller.rb:
class LocationsController < ApplicationController
helper_method :sort_column, :sort_direction
before_action :set_location, only: [:show, :edit, :update, :destroy]
def index
#locations = Location.all
# For sortable columns
#locations = Location.order(sort_column + " " + sort_direction)
end
def show
end
def new
#location= Location.new({:address=> "Use W E etc and St without PERIODS"})
repopulateResidResto()
end
def edit
end
def create
# Instantiate a new object using form parameters (notes here from Lynda>Skoglund)
#location = Location.new(location_params)
# Save the object
respond_to do |format|
if #location.save
# If save succeeds, redirect to the index action
format.html { redirect_to #location, notice: 'Address was successfully created.' }
format.json { render :show, status: :created, location: #location}
else
# If save fails, redisplay the form with information user filled in
format.html { render :new }
format.json { render json: #location.errors, status: :unprocessable_entity }
end
end
repopulateResidResto()
end # end create
def update
respond_to do |format|
if #location.update(location_params)
# If update succeeds, redirect to the show page
format.html { redirect_to #location, notice: 'Address was successfully updated.' }
format.json { render :show, status: :ok, location: #location }
else
# If update fails, redisplay the edit form for fixing
format.html { render :edit }
format.json { render json: #location.errors, status: :unprocessable_entity }
end
end
repopulateResidResto()
end # End update
def destroy
location = #location.destroy
respond_to do |format|
format.html { redirect_to locations_url, notice: "Location '#{location}' was successfully destroyed." }
format.json { head :no_content }
end
repopulateResidResto()
end
private
# Use callbacks to share common setup or constraints between actions.
def set_location
#location = Location.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def location_params
params.require(:location).permit(:address, :city, :state, :longitude, :latitude, :geom, :coords_not_locked, :geocoded_with, :extant, :current_description, :source, :ref_link, :notes)
end
def sort_column
Location.column_names.include?(params[:sort]) ? params[:sort] : "address"
end
def sort_direction
%w[asc desc].include?(params[:direction]) ? params[:direction] : "asc"
end
end
locations.yml:
one:
address: 1 Address1
city: Los Angeles
state: California
longitude: 99.99
latitude: 99.99
extant: false
current_description: MyString2
notes: Notes1
source: Source1
geocoded_with: geocoded_with_1
coords_not_locked: false
ref_link: ref_link_1
geom: 0101000020E61000008B187618938F5DC0C2189128B4064140
two:
address: 2 Address2
city: Los Angeles
state: California
longitude: 9.99
latitude: 9.99
extant: true
current_description: MyString
notes: MyString
source: MyString
geocoded_with: MyString
coords_not_locked: true
ref_link: MyString
geom: 0101000020E61000007B4963B48E8F5DC0467C2766BD064140
three:
address: 3 Address3
city: Los Angeles
state: California
longitude: 9.99
latitude: 9.99
extant: true
current_description: MyString
notes: MyString3
source: MyString3
geocoded_with: MyString3
coords_not_locked: true
ref_link: MyString3
geom: 0101000020E61000007B4963B48E8F5DC0467C2766BD064140
The model, location.rb:
class Location < ActiveRecord::Base
has_many :years, dependent: :destroy
has_many :people, through: :years
has_many :resto_resid_lines
def longlat
"#{longitude} #{latitude}"
end
def notes_plus_geocode
if notes == ""
"#{geocoded_with}"
else
"#{notes} #{geocoded_with}"
end
end
def full_address
full_address = "#{address}, #{city}, #{state}"
end
# For next and previous in show.
def next
Location.where(["id > ?", id]).first
end
def previous
Location.where(["id < ?", id]).last
end
geocoded_by :full_address
after_validation :geocode, :if => :coords_not_locked?
validates :address, length: { minimum: 5, maximum: 50 }, uniqueness: true
end
test_helper.rb
require 'simplecov'
SimpleCov.start
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
require "minitest/reporters"
Minitest::Reporters.use!
class ActiveSupport::TestCase
fixtures :all
# Returns true if a test user is logged in.
def is_logged_in?
!session[:user_id].nil?
end
# Logs in a test user.
def log_in_as(user, options = {})
password = options[:password] || 'password'
remember_me = options[:remember_me] || '1'
if integration_test?
post login_path, session: { email: user.email,
password: password,
remember_me: remember_me }
else
session[:user_id] = user.id
end
end
private
# Returns true inside an integration test.
def integration_test?
defined?(post_via_redirect)
end
end
If I turn the debugger on in the test, #location is
(byebug) pp #location
#<Location:0x007ff26ffa1ba8
id: 980190962,
address: "MyString21",
city: "MyString23",
state: "MyString25",
longitude: #<BigDecimal:7ff26ff96b40,'0.9999E2',18(27)>,
latitude: #<BigDecimal:7ff26ff96a50,'0.9999E2',18(27)>,
extant: false,
current_description: "MyString2",
notes: "MyString24",
created_at: Sun, 05 Mar 2017 18:46:12 UTC +00:00,
updated_at: Sun, 05 Mar 2017 18:46:12 UTC +00:00,
geom: "0101000020E61000008B187618938F5DC0C2189128B4064140",
source: "MyString",
geocoded_with: "MyString",
coords_not_locked: false,
ref_link: "MyString">
#<Location id: 980190962, address: "MyString21", city: "MyString23", state: "MyString25", longitude: #<BigDecimal:7ff26ff96b40,'0.9999E2',18(27)>, latitude: #<BigDecimal:7ff26ff96a50,'0.9999E2',18(27)>, extant: false, current_description: "MyString2", notes: "MyString24", created_at: "2017-03-05 18:46:12", updated_at: "2017-03-05 18:46:12", geom: "0101000020E61000008B187618938F5DC0C2189128B4064140", source: "MyString", geocoded_with: "MyString", coords_not_locked: false, ref_link: "MyString"
I'm not sure what to expect for this.
One posting that seemed relevant "User.count" didn't change by 1 - Rails had incomplete yml—I've triple checked mine, but maybe still missing something.
#ArtOfCode. Creating in console (I think this is what you're asking). And since id is nil and it doesn't appear in the database, you may be on the right track:
irb(main):004:0> location = Location.create( address: "1 Address1", city: "Los Angeles", state: "California", longitude: 99.99, latitude: 99.99, extant: false, current_description: "MyString2", notes: "MyString24", source: "MyString", geocoded_with: "MyString", coords_not_locked: false, ref_link: "MyString", geom: "0101000020E61000008B187618938F5DC0C2189128B4064140")
(0.2ms) BEGIN
Location Exists (0.4ms) SELECT 1 AS one FROM "locations" WHERE "locations"."address" = '1 Address1' LIMIT 1
SQL (2.5ms) INSERT INTO "locations" ("address", "state", "longitude", "latitude", "extant", "current_description", "notes", "source", "geocoded_with", "coords_not_locked", "ref_link", "geom", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) RETURNING "id" [["address", "1 Address1"], ["state", "California"], ["longitude", "99.99"], ["latitude", "99.99"], ["extant", "f"], ["current_description", "MyString2"], ["notes", "MyString24"], ["source", "MyString"], ["geocoded_with", "MyString"], ["coords_not_locked", "f"], ["ref_link", "MyString"], ["geom", "0101000020E61000008B187618938F5DC0C2189128B4064140"], ["created_at", "2017-03-05 20:00:28.246188"], ["updated_at", "2017-03-05 20:00:28.246188"]]
(2.1ms) COMMIT
#<Location:0x007fe851a9bac8> {
:id => 177,
:address => "1 Address1",
:city => "Los Angeles",
:state => "California",
:longitude => 99.99,
:latitude => 99.99,
:extant => false,
:current_description => "MyString2",
:notes => "MyString24",
:created_at => Sun, 05 Mar 2017 20:00:28 UTC +00:00,
:updated_at => Sun, 05 Mar 2017 20:00:28 UTC +00:00,
:geom => "0101000020E61000008B187618938F5DC0C2189128B4064140",
:source => "MyString",
:geocoded_with => "MyString",
:coords_not_locked => false,
:ref_link => "MyString"
}
The application is incomplete, but you can see a location here. Not currently allowing sign-ups, so obviously create can't be used. The addresses are more than 100 years old and the geo coordinates may not be generated. geom is created later in PostGIS.
I imagine there is a simple solution, but it alludes me. gem 'rails' , '4.2.7' and ruby '2.3.1'
Fixtures create database entries automatically. Your location fixture one exists in the database.
So when you try a post to create a new location and you specify...
post :create, location: { address: #location.address,
You are trying to create a location with an address that already exists, but
validates :address, length: { minimum: 5, maximum: 50 }, uniqueness: true
...specifies that the address must be unique, so the record you're attempting to post is not valid because it has the same address as an existing record.
Simply change the address in your post :create call
post :create, location: { address: "1 A New Address",
I'm building an Events app in Rails and I've hit the error above which relates to this method in my Model -
def validate_availability
errors.add(:base, 'event is fully booked') if booking.count >= event.number_of_spaces
end
The purpose of the method is to avoid over-booking of an event whereby a specific number of spaces are available. In my Controller I have the following code -
Controller#Create
def create
#event = Event.find(params[:event_id])
#booking = #event.bookings.new(booking_params)
#booking.user = current_user
if
#booking.set_booking
flash[:success] = "Your place on our event has been booked"
redirect_to event_booking_path(#event, #booking)
else
flash[:error] = "Booking unsuccessful"
render "new"
end
if #event.is_free?
#booking.save(booking_params)
end
if booking.count >= #event.number_of_spaces
flash[:error] = "Sorry, this event is now fully booked"
render "new"
end
end
I need to define booking.count in my controller but not sure what would work - tried a few things but nothings working. I have the following in my schema -
create_table "bookings", force: :cascade do |t|
t.integer "event_id"
t.integer "user_id"
t.string "stripe_token"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "quantity", default: 1
t.integer "total_amount"
t.string "stripe_charge_id"
t.string "booking_number"
end
The booking.count would rely upon the quantity of spaces/bookings a user wishes to make versus the number of spaces remaining but how do I express this? Do I need a total_bookings column in my table or a separate method?
UPDATE -
Booking.rb
class Booking < ActiveRecord::Base
belongs_to :event
belongs_to :user
before_create :set_booking_number
validates :quantity, presence: true, numericality: { greater_than_or_equal_to: 0 }
validates :total_amount, presence: true, numericality: { greater_than_or_equal_to: 0 }
validate(:validate_booking)
validate(:validate_availability)
def set_booking_number
self.booking_number = "MAMA" + '- ' + SecureRandom.hex(4).upcase
end
def set_booking
if self.event.is_free?
self.total_amount = 0
save!
else
self.total_amount = event.price_pennies * self.quantity
begin
charge = Stripe::Charge.create(
amount: total_amount,
currency: "gbp",
source: stripe_token,
description: "Booking created for amount #{total_amount}")
self.stripe_charge_id = charge.id
save!
rescue Stripe::CardError => e
# if this fails stripe_charge_id will be null, but in case of update we just set it to nil again
self.stripe_charge_id = nil
# we check in validatition if nil
end
end
end
def validate_booking
# stripe_charge_id must be set for not free events
unless self.event.is_free?
return !self.stripe_charge_id.nil?
end
end
private
def validate_availability
errors.add(:base, 'event is fully booked') if event.bookings.count >= event.number_of_spaces
end
end
For the counts of booking table, you should have a booking_count field in events table. Use the counter cache for this. For more details check http://guides.rubyonrails.org/association_basics.html. This is very helpful when records are large.
Your migration for adding column should be similar as below:
def change
add_column :events, :bookings_count, :integer, default: 0
Event.reset_column_information
Event.all.each do |e|
Event.update_counters e.id, :bookings_count => e.bookings.length
end
end
I'm new to Rails. Running Rails 4, and gem ajax-datatables-rails.
I have a few instances of datatables that are working without issue, but one table has an error when I try to sort any column descending. I can click on the header of any column and sort ascending. But if I click on that header again I get the following error:
DataTables warning: table id=DataTables_Table_0 - Ajax error. For more information about this error, please see http://datatables.net/tn/7
Log shows this after getting the error:
Completed 500 Internal Server Error in 14ms (ActiveRecord: 2.1ms)
NoMethodError (undefined method `name' for nil:NilClass):
app/datatables/animal_registration_datatable.rb:29:in `block in data'
app/datatables/animal_registration_datatable.rb:25:in `data'
app/controllers/animal_registrations_controller.rb:8:in `block (2 levels) in index'
app/controllers/animal_registrations_controller.rb:5:in `index'
animal_registration_datatable.rb
class AnimalRegistrationDatatable < AjaxDatatablesRails::Base
include AjaxDatatablesRails::Extensions::Kaminari
def sortable_columns
# Declare strings in this format: ModelName.column_name
if breeder?
#sortable_columns ||= %w(AnimalRegistration.created_at Animal.name Animal.tag_number AnimalRegistration.status)
else
#sortable_columns ||= %w(AnimalRegistration.created_at Animal.name Contact.last_name Contact.farm_name)
end
end
def searchable_columns
# Declare strings in this format: ModelName.column_name
if breeder?
#searchable_columns ||= %w(Animal.name Animal.tag_number AnimalRegistration.status)
else
#searchable_columns ||= %w(AnimalRegistration.farm_name Animal.name Contact.last_name Contact.first_name AnimalRegistration.created_at)
end
end
private
def data
records.map do |record|
if breeder?
{
'0' => record.created_at.strftime('%x - ''%l:%m %p'),
'1' => record.animal.name,
'2' => record.animal.tag_number,
'3' => record.status,
'DT_RowId' => record.id
}
else
{
'0' => record.created_at.strftime('%x - ''%l:%m %p'),
'1' => record.animal.try(:name),
'2' => record.breeder_contact_id ? record.breeder_contact.last_name + ', ' + record.breeder_contact.first_name : "",
'3' => record.breeder_contact_id ? record.breeder_contact.farm_name : "",
'4' => record.datatable_row_controls,
'DT_RowId' => record.id
}
end
end
end
def user
#user ||= options[:user] #if #user is null, set it to options[:user]
end
def breeder?
! user.organization
end
def status
#status ||= options[:status]
#status ||= "pending"
end
def get_raw_records
if breeder?
AnimalRegistration.where(user_id: user.id).includes(:animal).references(:animal).distinct
else
AnimalRegistration.where(organization_id: user.organization.id, status: status).includes(:animal, :breeder_contact).references(:animal, :breeder_contact).distinct
end
end
# ==== Insert 'presenter'-like methods below if necessary
end
Note that I am logged in as a breeder (if breeder? = true). Note also that when logged in as org (if breeder? = false), this error does not occur.
From animal_registrations_controller.rb:
def index
respond_to do |format|
format.html
format.json do
render json: AnimalRegistrationDatatable.new(view_context, user: current_user, status: params[:status])
end
end
end
animal_registrations.js.coffee:
$ ->
dt = $("table.animal-registrations.ajax-table")
if dt.hasClass("org-admin")
dtCols = [
{ data: '0' }
{ data: '1' }
{ data: '2' }
{ data: '3' }
{ data: '4', orderable: false }
]
else
dtCols = [
{ data: '0' }
{ data: '1' }
{ data: '2' }
{ data: '3' }
]
$("table.animal-registrations.ajax-table").DataTable(
processing: true
serverSide: true
ajax: $('table.animals').data('source')
pagingType: 'full'
pageLength: 20
lengthChange: false
language:
search: "<i class='fa fa-search'/>"
sFilterInput: "form-control input-lg"
# drawCallback: (settings) ->
# bindAnimalRowClickDatatable()
columns: dtCols
)
Note that if dt.hasClass("org-admin") is false.
Lots of moving parts here. What I can't figure out is why it would work when sorted ascending but not descending.
Thanks for any help.