When using nested forms with Oracle DB, Rails renders a decimal/float (e.g. 10010.0) instead of a fixnum (e.g. 10010) for all integer fields, including the id field, resulting in exceptions when updating. With SQLite it works as expected.
Why does this happen and where do things go wrong??
The following code demonstrates the issue:
Models
class Broker < ActiveRecord::Base
has_many :execution_groups, dependent: :destroy
accepts_nested_attributes_for :execution_groups, allow_destroy: true
end
class ExecutionGroup < ActiveRecord::Base
belongs_to :broker
end
View
= form_for( #broker, html: { class: 'form-horizontal'} ) do |f|
= f.fields_for :execution_groups, include_id: true do |eg_form|
= eg_form.hidden_field :id
Result in Browser when using SQLite
...
<input id="broker_execution_groups_attributes_0_id"
name="broker[execution_groups_attributes][0][id]"
type="hidden"
value="10010" />
...
This works as expected, the nested model is updated.
Result in Browser when using Oracle
...
<input id="broker_execution_groups_attributes_1_id"
name="broker[execution_groups_attributes][1][id]"
type="hidden"
value="10010.0" />
...
This crashes with a neat exception:
ActiveRecord::RecordNotFound in BrokersController#update
Couldn't find ExecutionGroup with ID=10010.0 for Broker with ID=10040
As to be expected, AR's not finding an ID like 10010.0 because there's only ID 10010 (without the .0) available.
Current Environment
.ruby-version (rvm configuration file)
jruby-1.7.19
Gemsfile.lock (excerpt)
rails (4.0.13)
actionmailer (= 4.0.13)
actionpack (= 4.0.13)
activerecord (= 4.0.13)
activesupport (= 4.0.13)
bundler (>= 1.3.0, < 2.0)
railties (= 4.0.13)
sprockets-rails (~> 2.0)
railties (4.0.13)
actionpack (= 4.0.13)
activesupport (= 4.0.13)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
activerecord-jdbc-adapter (1.3.19)
activerecord (>= 2.2)
activerecord-jdbcsqlite3-adapter (1.3.19)
activerecord-jdbc-adapter (~> 1.3.19)
jdbc-sqlite3 (>= 3.7.2, < 3.9)
jdbc-sqlite3 (3.8.11.2)
config/database.yml
Oracle via JDBC
development:
url: jdbc:oracle:thin:#mydbhost:1522:myschema
username: myuser
password: secret
SQLite
development:
adapter: sqlite3
database: db/development.sqlite3
Solution
Digging deeper into ActiveRecord I found that specifically overwriting the id_before_type_cast method for the model does the trick:
class ExecutionGroup < ActiveRecord::Base
belongs_to :broker
def id_before_type_cast
Integer( self.id ) unless self.id.nil?
end
end
While this does the trick, the *_before_type_cast needs to be defined for any Fixnum column or you'll get the same problem with the values.
Debugging details:
Stepping into ActionView::Helpers::Tags::Base.value_before_type_cast(object) I get the following status:
# for both SQLite and Oracle
object.class == ExecutionGroup # -> true
object.respond_to?(method_before_type_cast) # -> true
# SQLite
object.id_before_type_cast # -> {Fixnum} 10010
# Oracle
object.id_before_type_cast # -> {BigDecimal} 10010.0
After applying the fix both Oracle and SQLite show the same behaviour.
object.id_before_type_cast # -> {Fixnum} 10010
Related
I am trying to set up a test on a very basic ruby project(not rails) with the factorybot gem, but can't find a way to make it work. I followed the guide https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md
which is just installing the gem, run bundle install and add to my spec/spec_helper.rb this configuration:
RSpec.configure do |config|
config.include FactoryBot::Syntax::Methods
config.before(:suite) do
FactoryBot.find_definitions
end
end
Then I created a factories/order_factories.rb file inside the spec folder like this:
FactoryBot.define do
factory :restaurant do
id { 3 }
cooking_time { 15 }
x { 0 }
y { 0}
end
factory :customer do
id { 1 }
x { 1 }
y { 1 }
end
end
and require it from the spec file of the object I want to test. The file is order_spec.rb like this :
require_relative './factories/order_factories'
let(:restaurant) { create(:restaurant) }
describe "Order", :order do
it "should be initialized with a hash of properties" do
properties = { :customer => 1, :restaurant => 3 }
order = Order.new(properties)
expect(order).to be_a(Order)
end
end
I already tried tones of other file organisation with proper require, but keep on having the FactoryBot constant not initialized. I wonder if my Gemfile.lock is not the origin of the problem:
GEM
remote: https://rubygems.org/
specs:
activesupport (6.1.3.2)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
concurrent-ruby (1.1.8)
diff-lcs (1.4.4)
factory_bot (6.1.0)
activesupport (>= 5.0.0)
i18n (1.8.10)
concurrent-ruby (~> 1.0)
minitest (5.14.4)
rspec (3.10.0)
rspec-core (~> 3.10.0)
rspec-expectations (~> 3.10.0)
rspec-mocks (~> 3.10.0)
rspec-core (3.10.1)
rspec-support (~> 3.10.0)
rspec-expectations (3.10.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.10.0)
rspec-mocks (3.10.2)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.10.0)
rspec-support (3.10.2)
tzinfo (2.0.4)
concurrent-ruby (~> 1.0)
zeitwerk (2.4.2)
PLATFORMS
x86_64-darwin-18
DEPENDENCIES
factory_bot
rspec (~> 3.0)
BUNDLED WITH
2.2.16
Is there something I am missing here?
my spec/spec_helper.rb file :
require "factory_bot"
RSpec.configure do |config|
config.include FactoryBot::Syntax::Methods
config.before(:suite) do
FactoryBot.find_definitions
end
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
config.shared_context_metadata_behavior = :apply_to_host_groups
end
I edited my order_spec.rb like this :
require_relative "./spec_helper"
require "factory_bot"
require_relative './factories/order_factories'
but still not working..
If you have a Rails model with an attribute named y, and you have a factory that sets this attribute, it freaks out FactoryBot. It's not FactoryBot's fault, see error https://github.com/thoughtbot/factory_bot/issues/1397
Solution is to set the y attribute via
add_attribute(:y) { 0 }
I am trying to connect to Oracle database using 'activerecord' and Ruby 1.8.7 and getting below error on my Windows 7 machine. I searched around for this issue and came across 1.8 and 1.9 ruby declaration of 'Hash' however I am using Ruby 1.8.7 and I feel I am using correct hash declaration, please correct me if I am wrong.
C:/Ruby187/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:29:in `gem_original_require': C:/Ruby187/lib/ruby/gems/1.8/gems/activerecord-oracle_enhancedadapter-1.5.3/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb:917: odd number list for Hash (SyntaxError)
read_committed: "READ COMMITTED",
^
C:/Ruby187/lib/ruby/gems/1.8/gems/activerecord-oracle_enhanced-adapter-1.5.3/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb:917: syntax error, unexpected ':', expecting '}'
read_committed: "READ COMMITTED",
^
C:/Ruby187/lib/ruby/gems/1.8/gems/activerecord-oracle_enhanced-adapter-1.5.3/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb:917: syntax error, unexpected ',', expecting kEND
C:/Ruby187/lib/ruby/gems/1.8/gems/activerecord-oracle_enhanced-adapter-1.5.3/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb:919: syntax error, unexpected '}', expecting kEND
C:/Ruby187/lib/ruby/gems/1.8/gems/activerecord-oracle_enhanced-adapter-1.5.3/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb:1471: dynamic constant assignment
DBMS_OUTPUT_BUFFER_SIZE = 10000 # can be 1-1000000
^
C:/Ruby187/lib/ruby/gems/1.8/gems/activerecord-oracle_enhanced-adapter-1.5.3/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb:1555: syntax error, unexpected $end, expecting kEND
from C:/Ruby187/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:29:in `require'
from C:/Ruby187/lib/ruby/gems/1.8/gems/activesupport-2.3.4/lib/active_support/dependencies.rb:156:in `require'
from C:/Ruby187/lib/ruby/gems/1.8/gems/activesupport-2.3.4/lib/active_support/dependencies.rb:521:in `new_constants_in'
from C:/Ruby187/lib/ruby/gems/1.8/gems/activesupport-2.3.4/lib/active_support/dependencies.rb:156:in `require'
from C:/Ruby187/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/connection_adapters/abstract/connection_specification.rb:71:in `establish_connection'
from oracle_conn_testing.rb:5
This is how my code looks like
require 'rubygems'
gem "activerecord-oracle_enhanced-adapter"
require 'active_record'
ActiveRecord::Base.establish_connection(
:adapter => "oracle_enhanced",
:database => "someurl.net:1523/ABCAD",
:username => "testing1",
:password => "testing1")
class TestTable < ActiveRecord::Base
set_table_name "TABLE_NAME"
set_primary_key "ID"
end
TestTable.find(:all).each do |tt|
p tt
end
nac = TestTable.new()
Additional Information:
I have below gems on my machine :
* LOCAL GEMS *
actionmailer (2.3.4)
actionpack (2.3.4)
activerecord (2.3.4)
activerecord-oracle_enhanced-adapter (1.5.3)
activeresource (2.3.4)
activesupport (2.3.4)
json (1.8.1)
mysql (2.9.1 x86-mingw32)
rack (1.0.1)
rails (2.3.4)
rake (10.1.1)
ruby-oci8 (2.1.7 x86-mingw32)
rubygems-update (1.4.2)
I use below Rubygems version:
C:\Users\tester1>gem -v
1.4.2
I tried to connect using OCI8 and I was able to get response out of Oracle database so there is no connectivity issue from my machine.
irb(main):006:0> OCI8.new('testing1', 'testing1', 'someurl.net:1523/ABCAD').exec('select sysdate from dual') do |r| puts r.join(', ') end
Mon Mar 10 15:09:23 -0400 2014
=> 1
I used below link as my reference:
http://www.oracle.com/webfolder/technetwork/tutorials/obe/db/oow10/rubyhol/instructions/rubyrails.htm
The error message shows that your error is coming from inside the activerecord-oracle_enhancedadapter gem, and that gem has a Ruby 1.9 style hash. You might find an older version of that gem that supports Ruby 1.8 and switch to that version.
I receive the following error when I run my spec file:
I've read over the following questions to no avail:
ArgumentError: wrong number of arguments (0 for 1)
FactoryGirl issues - `factory': wrong number of arguments (0 for 1) (ArgumentError)
rspec not running because of factorygirl
ArgumentError in rspec
I'm not sure that I've set up my Ruby project with rspec and factory_girl correctly. Here are the associated files:
player.rb
class Player
attr_accessor :name
def initialize(string)
#name = string
end
end
players.rb (factory)
require './player'
FactoryGirl.define do
factory :player do
name "Cliff Levingston"
end
end
player_spec.rb
require 'spec_helper'
describe 'Player' do
context 'when created' do
it "should include a #name" do
player1 = FactoryGirl.build :player
# player1.name = "Gerald"
expect(player1.name).to eql "Cliff Levingston"
end
end
end
Gemfile
source 'hhtps://rubygems.org'
gem 'guard'
gem 'guard-shell'
gem 'rspec'
gem 'factory_girl', '~> 4.0'
gem 'rb-fsevent', '~> 0.9'
Gemfile.lock
GEM
remote: hhtps://rubygems.org/
specs:
activesupport (4.0.1)
i18n (~> 0.6, >= 0.6.4)
minitest (~> 4.2)
multi_json (~> 1.3)
thread_safe (~> 0.1)
tzinfo (~> 0.3.37)
atomic (1.1.14)
celluloid (0.15.2)
timers (~> 1.1.0)
coderay (1.0.9)
diff-lcs (1.2.5)
factory_girl (4.3.0)
activesupport (>= 3.0.0)
ffi (1.9.3)
formatador (0.2.4)
guard (2.2.3)
formatador (>= 0.2.4)
listen (~> 2.1)
lumberjack (~> 1.0)
pry (>= 0.9.12)
thor (>= 0.18.1)
guard-shell (0.5.1)
guard (>= 1.1.0)
i18n (0.6.5)
listen (2.2.0)
celluloid (>= 0.15.2)
rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9)
lumberjack (1.0.4)
method_source (0.8.2)
minitest (4.7.5)
multi_json (1.8.2)
pry (0.9.12.2)
coderay (~> 1.0.5)
method_source (~> 0.8)
slop (~> 3.4)
rb-fsevent (0.9.3)
rb-inotify (0.9.2)
ffi (>= 0.5.0)
rspec (2.14.1)
rspec-core (~> 2.14.0)
rspec-expectations (~> 2.14.0)
rspec-mocks (~> 2.14.0)
rspec-core (2.14.7)
rspec-expectations (2.14.4)
diff-lcs (>= 1.1.3, < 2.0)
rspec-mocks (2.14.4)
slop (3.4.6)
thor (0.18.1)
thread_safe (0.1.3)
atomic
timers (1.1.0)
tzinfo (0.3.38)
PLATFORMS
ruby
DEPENDENCIES
factory_girl (~> 4.0)
guard
guard-shell
rb-fsevent (~> 0.9)
rspec
spec_helper.rb
require 'rspec'
require 'factory_girl'
RSpec.configure do |config|
# FactoryGirl
FactoryGirl.find_definitions
# Use color in STDOUT
config.color_enabled = true
# Use color not only in STDOUT but also in pagers and files
config.tty = true
# Use the specified formatter
config.formatter = :documentation # :progress, :html, :textmate
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = "random"
end
I'd like to better understand what I omitted or need to add in order to remove the ArgumentError (0 for 1).
Thanks in advance.
I believe the issue is with your player model requiring an argument at initialization.
Try this instead:
class Player
attr_accessor :name
def initialize(options={})
#name = options[:name]
end
end
When FactoryGirl initializes the model, it will initialize with a nil name attribute like this:
1.9.3p448 :013 > Player.new
#<Player:0x000000017acff0 #name=nil>
You can then define the name as you intend in your commented out line. This will also allow you to initialize a Player with a hash like:
1.9.3p448 :012 > Player.new(name: "something")
#<Player:0x00000003b53008 #name="something">
I just upgraded to watir 4.0.2 from watir 2.0.4 and i am getting the below error,
C:/Ruby187/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:60:in `gem_original
_require': no such file to load -- watir/testcase (LoadError)
I searched about the error and was not able to find a solution to it.
Gem List
abstract (1.0.0)
actionmailer (3.2.8, 3.0.0)
actionpack (3.2.8, 3.0.0)
activemodel (3.2.8, 3.0.0)
activerecord (3.2.8, 3.0.0)
activeresource (3.2.8, 3.0.0)
activesupport (3.2.8, 3.0.0)
addressable (2.3.2)
akami (1.2.0)
arel (3.0.2, 1.0.1)
Ascii85 (1.0.1)
builder (3.0.0, 2.1.2)
bundler (1.0.22)
childprocess (0.3.6)
commandline (0.7.10)
commonwatir (4.0.0, 2.0.4)
erubis (2.7.0, 2.6.6)
ffi (1.1.5)
gyoku (0.4.6)
hike (1.2.1)
hoe (3.0.8)
httpi (0.9.7)
i18n (0.6.1, 0.4.2)
journey (1.0.4)
libwebsocket (0.1.5)
mail (2.4.4, 2.2.19)
mime-types (1.19, 1.18)
mini_magick (3.2.1)
multi_json (1.3.6)
mysql2 (0.3.11 x86-mingw32, 0.2.18 x86-mingw32, 0.2.6 x86-mingw32)
nokogiri (1.5.5 x86-mingw32)
nori (1.1.3)
pdf-reader (1.1.1)
polyglot (0.3.3)
rack (1.4.1, 1.2.5)
rack-cache (1.2)
rack-mount (0.6.14)
rack-ssl (1.3.2)
rack-test (0.6.2, 0.5.7)
rails (3.0.0)
railties (3.0.0)
rake (0.8.7)
rautomation (0.7.3, 0.6.3)
ruby-rc4 (0.1.5)
rubygems-update (1.8.24)
rubyzip (0.9.9)
s4t-utils (1.0.4)
savon (0.9.9)
selenium-webdriver (2.26.0)
sprockets (2.1.3)
sqlite3 (1.3.6 x86-mingw32)
sqlite3-ruby (1.3.3)
subexec (0.0.4)
text-format (1.0.0)
text-hyphen (1.0.2)
thor (0.14.6)
tilt (1.3.3)
treetop (1.4.10)
tzinfo (0.3.33)
user-choices (1.1.6.1)
wasabi (2.1.0)
watir (4.0.2 x86-mingw32, 2.0.4)
watir-classic (3.3.0)
watir-webdriver (0.6.2)
websocket (1.0.6)
win32-api (1.4.8 x86-mingw32)
win32-process (0.6.6)
win32screenshot (1.0.7)
windows-api (0.4.2)
windows-pr (1.2.2)
xml-simple (1.1.1)
Ruby Version:ruby 1.8.7 (2010-08-16 patchlevel 302) [i386-mingw32]
Any idea on this?
watir/testcase was removed from Watir recently. I can not find when it was removed, but the information is in CHANGES file or in Git history.
While it would probably be better to move away from Watir::TestCase, if you really need or want to use it, you can re-create it by copying the files from 3.0.
Assume you are using Ruby 1.8, which still has the test-unit gem installed by default, you can do the following:
1) Create a file named 'watir_testcase.rb' with the following code, which is basically a copy of the testcase.rb and assertions.rb file from 3.0:
require 'watir-classic'
require 'test/unit'
require 'test/unit/assertions'
module Watir
# Verification methods used by Watir::TestCase
module Assertions
include Test::Unit::Assertions
# Log a failure if the boolean is true. The message is the failure message logged.
# Whether true or false, the assertion count is incremented.
def verify boolean, message = 'verify failed.'
add_assertion
add_failure message.to_s, caller unless boolean
end
def verify_equal expected, actual, message=nil
full_message = build_message(message, <<EOT, expected, actual)
<?> expected but was
<?>.
EOT
verify(expected == actual, full_message)
end
def verify_match pattern, string, message=nil
pattern = case(pattern)
when String
Regexp.new(Regexp.escape(pattern))
else
pattern
end
full_message = build_message(message, "<?> expected to be =~\n<?>.", string, pattern)
verify(string =~ pattern, full_message)
end
end
end
module Test::Unit::Assertions
def assert_false(boolean, message=nil)
_wrap_assertion do
assert_block("assert should not be called with a block.") { !block_given? }
assert_block(build_message(message, "<?> is not false.", boolean)) { !boolean }
end
end
end
module Watir
# This is a 'test/unit' testcase customized to exeucte test methods sequentially by default
# and extra assertions
#
class TestCase < Test::Unit::TestCase
include Watir::Assertions
##order = :sequentially
def initialize name
throw :invalid_test if name == :default_test && self.class == Watir::TestCase
super
end
class << self
attr_accessor :test_methods, :order
def test_methods
#test_methods ||= []
end
def order
#order || ##order
end
def default_order= order
##order = order
end
def sorted_test_methods
case order
when :alphabetically then test_methods.sort
when :sequentially then test_methods
when :reversed_sequentially then test_methods.reverse
when :reversed_alphabetically then test_methods.sort.reverse
else raise ArgumentError, "Execute option not supported: #{#order}"
end
end
def suite
suite = Test::Unit::TestSuite.new(name)
sorted_test_methods.each do |test|
catch :invalid_test do
suite << new(test)
end
end
if (suite.empty?)
catch :invalid_test do
suite << new(:default_test)
end
end
return suite
end
def method_added id
name = id.id2name
test_methods << name if name =~ /^test./
end
def execute order
#order = order
end
end
public :add_assertion
end
end
2) In your test case files, change the:
require 'watir/testcase'
to require the newly created file:
require './watir_testcase'
(ensuring that the path is correct for wherever you saved the file)
I've grabbed the latest code base of a gem called socialstream but I'm noticing an issue with file uploads on windows machines. The issue seems to be with the code below...
# Monkey patches to Ruby on Rails
#
# Use unix file util to prove the content type sent by the browser
class ActionDispatch::Http::UploadedFile
def initialize_with_magic(*args, &block)
initialize_without_magic(*args, &block)
if (unix_file = `which file`.chomp).present? && File.exists?(unix_file)
`#{ unix_file } -v 2>&1` =~ /^file-(.*)$/
version = $1
#content_type =
if version >= "4.24"
`#{ unix_file } -b --mime-type #{ #tempfile.path }`.chomp
else
`#{ unix_file } -bi #{ #tempfile.path }`.chomp =~ /(\w*\/[\w+-\.]*)/
$1
end
end
end
alias_method_chain :initialize, :magic
end
the error is as follows
NoMethodError (undefined method chomp' for nil:NilClass):
social_stream-base (0.22.0) lib/rails/social_stream.rb:8:ininitialize_with_magic'
actionpack (3.2.5) lib/action_dispatch/http/upload.rb:39:in new'
actionpack (3.2.5) lib/action_dispatch/http/upload.rb:39:innormalize_parameters'
actionpack (3.2.5) lib/action_dispatch/http/parameters.rb:73:in block in normalize_parameters'
actionpack (3.2.5) lib/action_dispatch/http/parameters.rb:73:ineach'
actionpack (3.2.5) lib/action_dispatch/http/parameters.rb:73:in normalize_parameters'
actionpack (3.2.5) lib/action_dispatch/http/upload.rb:41:innormalize_parameters'
actionpack (3.2.5) lib/action_dispatch/http/parameters.rb:73:in block in normalize_parameters'
actionpack (3.2.5) lib/action_dispatch/http/parameters.rb:73:ineach'
actionpack (3.2.5) lib/action_dispatch/http/parameters.rb:73:in normalize_parameters'
actionpack (3.2.5) lib/action_dispatch/http/upload.rb:41:innormalize_parameters'
Is there a way to make this work on windows, either by using a gem, something i can install on windows, or rewriting the file?
Either delete or comment out the line:
alias_method_chain :initialize, :magic
This will stop it from hooking into ActionDispatch::HTTP::UploadFile#initialize
This also means you won't get its benefit of "proving" the content-type, but I don't know if that is really necessary for your application.