How to avoid ActiveRecord::InvalidForeignKey? - ruby-on-rails

I can't figure out how to fix RSpec errors.
My apps is like this.
There's 3 models, CompanyBag, CompanyBagTarget, Company.
CompanyBag is a group of Companies. CompanyBagTarget is association table between CompanyBag and Company.
Probably, CompanyBagTarget doesn't match appropriate Company.
Now, RSpec error is here.
1) CompanyBagsController POST #create creates a new ComapnyBag
Failure/Error: t.save!
ActiveRecord::InvalidForeignKey:
Mysql2::Error: Cannot add or update a child row: a foreign key constraint fails (`eiicon`.`company_bag_targets`, CONSTRAINT `fk_bag_targets_company` FOREIGN KEY (`company_id`) REFERENCES `company` (`id`)): INSERT INTO `company_bag_targets` (`company_bag_id`, `company_id`, `display_order`) VALUES (38, 13, 0)
# ./app/models/company_bag.rb:22:in `block in update_targets!'
# ./app/models/company_bag.rb:16:in `each'
# ./app/models/company_bag.rb:16:in `each_with_index'
# ./app/models/company_bag.rb:16:in `update_targets!'
# ./app/controllers/company_bags_controller.rb:52:in `create'
# ./spec/controllers/company_bag_controller_spec.rb:55:in `block (4 levels) in <top (required)>'
# ./spec/controllers/company_bag_controller_spec.rb:54:in `block (3 levels) in <top (required)>'
# ------------------
# --- Caused by: ---
# Mysql2::Error:
# Cannot add or update a child row: a foreign key constraint fails (`eiicon`.`company_bag_targets`, CONSTRAINT `fk_bag_targets_company` FOREIGN KEY (`company_id`) REFERENCES `company` (`id`))
# ./app/models/company_bag.rb:22:in `block in update_targets!'
2) CompanyBagsController POST #create creates a new ComapnyBagTarget
Failure/Error: t.save!
ActiveRecord::InvalidForeignKey:
Mysql2::Error: Cannot add or update a child row: a foreign key constraint fails (`eiicon`.`company_bag_targets`, CONSTRAINT `fk_bag_targets_company` FOREIGN KEY (`company_id`) REFERENCES `company` (`id`)): INSERT INTO `company_bag_targets` (`company_bag_id`, `company_id`, `display_order`) VALUES (39, 13, 0)
# ./app/models/company_bag.rb:22:in `block in update_targets!'
# ./app/models/company_bag.rb:16:in `each'
# ./app/models/company_bag.rb:16:in `each_with_index'
# ./app/models/company_bag.rb:16:in `update_targets!'
# ./app/controllers/company_bags_controller.rb:52:in `create'
# ./spec/controllers/company_bag_controller_spec.rb:62:in `block (4 levels) in <top (required)>'
# ./spec/controllers/company_bag_controller_spec.rb:61:in `block (3 levels) in <top (required)>'
# ------------------
# --- Caused by: ---
# Mysql2::Error:
# Cannot add or update a child row: a foreign key constraint fails (`eiicon`.`company_bag_targets`, CONSTRAINT `fk_bag_targets_company` FOREIGN KEY (`company_id`) REFERENCES `company` (`id`))
# ./app/models/company_bag.rb:22:in `block in update_targets!'
Next here's model's definitions.
class CompanyBag < ApplicationRecord
has_many :targets, class_name: "CompanyBagTarget"
def update_targets!(company_ids:)
destroy_targets
company_ids.reverse.each_with_index do |id, idex|
t = CompanyBagTarget.new
t.company_bag_id = self.id
t.company_id = id
t.display_order = idex
t.save!
end
end
class CompanyBagTarget < ApplicationRecord
belongs_to :company_target
Next, here's controller.
def create
#bag = CompanyBag.new(bag_params)
#target_ids = params[:company_bag][:target_ids].split(",").map{|n| n.split("_")[0].to_i}
if bag_params[:banner].present?
filename = upload_image
#bag.banner = filename
end
if #bag.save
#bag.update_targets!(company_ids: #target_ids)
redirect_to action: 'index'
else
flash[:alert] = #bag.errors.messages.values[0][0]
#target_ids = params[:company_bag][:target_ids]
render 'new'
end
end
Finally, here's controller's spec.
require 'rails_helper'
RSpec.describe CompanyBagsController, type: :controller do
login_admin
let(:user) { #admin }
let(:company_bag) { FactoryGirl.create(:some_company_bag) }
let(:company_bag_target) { {target_ids: "1_インテリジェンステスト株式会社,21_>グローバルウォーカーズ株式会社,33_株式会社コーデセブン"} }
let(:companies) { FactoryGirl.create(:companies) }
let(:valid_attributes) {
{
label: 1,
banner: "https://s3-ap-northeast-1.amazonaws.com/eiicon.prd.contents/image/bags/6dbd5b5b-f242-4e4a-bcd3-de3edc9ae08d.png",
title: "test title",
description: "test title",
target_ids: "1_インテリジェンステスト株式会社,21_グローバルウォーカーズ株>式会社,33_株式会社コーデセブン"
}
}
describe 'POST #create' do
it 'creates a new ComapnyBag' do
expect{
post :create, params: {company_bag: valid_attributes}, session: valid_session
}.to change(CompanyBag, :count).by(1)
end
it 'creates a new ComapnyBagTarget' do
expect{
post :create, params: {company_bag: valid_attributes}, session: valid_session
}.to change(CompanyBagTarget, :count).by(1)
end
Anyone, please. Thanks in advance.
[Appendix]
Next, here's factories.
FactoryGirl.define do
factory :some_company_bag, class: CompanyBag do
label "some label"
banner "https://s3-ap-northeast-1.amazonaws.com/eiicon.prd.contents/image/bags/6dbd5b5b-f242-4e4a-bcd3-de3edc9ae08d.png"
title "Best Company Title Ever!!"
description "Some says description"
html_description "Html desc"
html_keyword "Html Kw"
end
factory :companies, class: Company do
name "複数テスト会社"
name_kana "フクスウテストカイシャ"
premium_status "free"
pr_status_id 0
is_valid 1
after(:create) do |c|
c.staff << FactoryGirl.create(:staff, company_id: c.id)
end
end
end
And tables.
create_table "company_bag_targets", primary_key: ["company_bag_id", "company_id"], force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4" do |t|
t.integer "company_bag_id", null: false
t.integer "company_id", null: false
t.integer "display_order", null: false
t.index ["company_id"], name: "fk_bag_targets_company", using: :btree
end
create_table "company_bags", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4" do |t|
t.string "label", limit: 100, null: false
t.string "banner", limit: 300
t.string "title", limit: 300
t.text "description", limit: 65535
t.string "html_description", limit: 300
t.string "html_keyword", limit: 300
end
create_table "company", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4" do |t|
t.string "name", null: false
t.string "name_kana"
t.integer "prefecture_id"
t.string "url", limit: 1023
t.date "establishment"

Related

Test fails for controller method rails

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

Testing create Action using RSpec in Rails

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

Rails Name Error - Undefined local variable or method `booking'

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

ActiveModel::MissingAttributeError (can't write unknown attribute 'Russian Federation'):

Getting a very strange error when running reduce on an activemodel relation. It seems like calling "c.name" in my reduce code causes the error. c.name returns the string "Russian Federation". Am I using reduce incorrectly?
Here is the error:
[2014-03-17T21:12:40.174655 #9240] FATAL -- :
ActiveModel::MissingAttributeError (can't write unknown attribute `Russian Federation'):
app/controllers/registrations_controller.rb:96:in `block in pluck_countries'
app/controllers/registrations_controller.rb:96:in `pluck_countries'
Larger stacktrace from the console:
#third_party_countries.reduce(#hsh) {|hsh, c| hsh[c.name] = ThirdPartyShipping.first }
ActiveModel::MissingAttributeError: can't write unknown attribute `Russian Federation'
from /var/www/html/babiators.com/landf/vendor/bundle/ruby/2.0.0/gems/activerecord-4.0.2/lib/active_record/attribute_methods/write.rb:47:in `write_attribute'
from /var/www/html/babiators.com/landf/vendor/bundle/ruby/2.0.0/gems/activerecord-4.0.2/lib/active_record/attribute_methods/dirty.rb:70:in `write_attribute'
from /var/www/html/babiators.com/landf/vendor/bundle/ruby/2.0.0/gems/activerecord-4.0.2/lib/active_record/attribute_methods.rb:341:in `[]='
from (irb):3:in `block in irb_binding'
from /var/www/html/babiators.com/landf/vendor/bundle/ruby/2.0.0/gems/activerecord-4.0.2/lib/active_record/relation/delegation.rb:63:in `each'
from /var/www/html/babiators.com/landf/vendor/bundle/ruby/2.0.0/gems/activerecord-4.0.2/lib/active_record/relation/delegation.rb:63:in `reduce'
from /var/www/html/babiators.com/landf/vendor/bundle/ruby/2.0.0/gems/activerecord-4.0.2/lib/active_record/relation/delegation.rb:63:in `method_missing'
from (irb):3
from /var/www/html/babiators.com/landf/vendor/bundle/ruby/2.0.0/gems/railties-4.0.2/lib/rails/commands/console.rb:90:in `start'
from /var/www/html/babiators.com/landf/vendor/bundle/ruby/2.0.0/gems/railties-4.0.2/lib/rails/commands/console.rb:9:in `start'
from /var/www/html/babiators.com/landf/vendor/bundle/ruby/2.0.0/gems/railties-4.0.2/lib/rails/commands.rb:62:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
Here is the code:
#third_party_countries = Country.third_party_countries
#hsh = HashWithIndifferentAccess.new
#third_party_countries.reduce(#hsh) {|hsh, c| hsh[c.name] = c.third_party_shipping }
Country schema:
create_table "countries", force: true do |t|
t.string "name"
t.float "shipping_rate"
t.integer "third_party_shipping_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "product_id"
end
Country model:
class Country < ActiveRecord::Base
belongs_to :third_party_shipping
has_and_belongs_to_many :products
has_many :addresses
validates_presence_of :name
validates_uniqueness_of :name
before_create :init
after_initialize :init
scope :shippable, -> { where(third_party_shipping_id: nil) }
scope :third_party_countries, -> { where.not(third_party_shipping_id: nil) }
def shipping_price
self.shipping_rate * 100
end
def free_shipping
self.shipping_rate <= 0 and self.third_party_shipping_id.nil?
end
def paid_shipping
!self.free_shipping
end
def shipping_display
if self.free_shipping
"free"
elsif self.paid_shipping
self.shipping_rate
end
end
private
def init
if self.shipping_rate.blank?
self.shipping_rate = 0
end
end
end
Since you're declaring #hsh outside the loop, you have no need of the extra complexity introduced by inject/reduce. Just use each:
#hsh = HashWithIndifferentAccess.new
#third_party_countries.each{ |c| #hsh[c.name] = c.third_party_shipping }
The problem with your existing code is that, with inject/reduce, the return value of the block is passed as the first argument to the next invocation. You need to return hsh from your block, otherwise the value of c.third_party_shipping is passed as hsh to the next invocation, and you're effectively doing c.third_party_shipping[c.name].
You could make it work by returning hsh...
#third_party_countries.reduce(#hsh) do |hsh, c|
hsh[c.name] = c.third_party_shipping
hsh
end
But you shouldn't. You don't need this functionality. each_with_object is the correct method to use:
#hsh = #third_party_countries.each_with_object(HashWithIndifferentAccess.new) do |hsh, c|
hsh[c.name] = c.third_party_shipping
end
You could also just map the collection to an array, and initialize your hash with that array:
#hsh = HashWithIndifferentAccess[#third_party_countries.map { |c| [c.name, c.third_party_shipping] }]
This relies on the ability to freely convert between arrays and hashes. The array [[a, b], [c, d]] converts to the hash { a => b, c => d }.

ActiveRecord::StatementInvalid - SQLite3::SQLException: no such column

When running my tests in RSpec, I get these errors:
Failures:
1) User micropost associations should have the right micropost in the right order
←[31mFailure/Error:←[0m ←[31m#user.microposts.should == [newer_micropost, older_micropost]←[0m
←[31mActiveRecord::StatementInvalid:←[0m
←[31mSQLite3::SQLException: no such column: micropost.created_at: SELECT "microposts".* FROM "microposts" WHERE "microposts"."user_id" = 1 ORD
ER BY micropost.created_at DESC←[0m
←[36m # C:in `load_target'←[0m
←[36m # ./spec/models/user_spec.rb:153:in `block (3 levels) in <top (required)>'←[0m
2) User micropost associations should destroy associated microposts
←[31mFailure/Error:←[0m ←[31mmicroposts = #user.microposts.dup←[0m
←[31mActiveRecord::StatementInvalid:←[0m
←[31mSQLite3::SQLException: no such column: micropost.created_at: SELECT "microposts".* FROM "microposts" WHERE "microposts"."user_id" = 1 ORD
ER BY micropost.created_at DESC←[0m
←[36m # C:in `load_target'←[0m
←[36m # ./spec/models/user_spec.rb:157:in `block (3 levels) in <top (required)>'←[0m
Finished in 5.18 seconds
←[31m97 examples, 2 failures←[0m
user_spec.rb:
require 'spec_helper'
describe User do
before do
#user = User.new(name: "John Smith", email: "john#example.com",
password: "password", password_confirmation: "password")
end
subject { #user }
it { should respond_to(:name) }
it { should respond_to(:email) }
it { should respond_to(:password_digest) }
it { should respond_to(:password) }
it { should respond_to(:password_confirmation) }
it { should respond_to(:remember_token) }
it { should respond_to(:admin) }
it { should respond_to(:authenticate) }
it { should respond_to(:microposts) }
it { should be_valid }
it { should_not be_admin }
describe "micropost associations" do
before { #user.save }
let!(:older_micropost) do
FactoryGirl.create(:micropost, user: #user, created_at: 1.day.ago)
end
let!(:newer_micropost) do
FactoryGirl.create(:micropost, user: #user, created_at: 1.hour.ago)
end
it "should have the right micropost in the right order" do
# user.micropost returns an array
#user.microposts.should == [newer_micropost, older_micropost]
end
it "should destroy associated microposts" do
microposts = #user.microposts.dup
#user.destroy
microposts.should_not be_empty
microposts.each do |micropost|
Micropost.find_by_id(micropost.id).should be_nil
end
end
end
end
schema.rb (shortened):
ActiveRecord::Schema.define(:version => 20131002154740) do
create_table "microposts", :force => true do |t|
t.string "content"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "microposts", ["user_id", "created_at"], :name => "index_microposts_on_user_id_and_created_at"
create_table "users", :force => true do |t|
.
.
.
.
end
end
Micropost model:
class Micropost < ActiveRecord::Base
attr_accessible :content
belongs_to :user
validates :user_id, presence: true
# Ensures the microposts are in descending (DESC) order
# from newest to oldest, (SQL syntax).
default_scope order: 'micropost.created_at DESC'
end
I have run bundle exec rake db:migrate along with bundle exec rake db:test:prepare, I have also reset the database and tried it again but this didn't work.
Specifically the error reads: SQLite3::SQLException: no such column: micropost.created_at: SELECT "microposts".* FROM "microposts" WHERE "microposts"."user_id" = 1 ORD
ER BY micropost.created_at DESC
Well, the SQL problem is that the table name on your sort column is singular rather than plural.
i.e. "ORDER BY micropost.created_at" should read "ORDER BY microposts.created_at".
If you also post your Micropost and User model source code, I might be able to tell if this is caused by a bug in your model code or a bug in ActiveRecord.
Which version of Rails are you using?

Resources