uninitialized constant ActiveRecord::RecordNotUnique - activerecord

I am using rails 2.3.4, rubygems 1.3.6, activerecord 3.1.0, windows 7 home basic
Here's my code:
def items
#products = ShopifyAPI::Product.find(:all)
#products.each do |a|
begin
#shop = Product.new(:title => a.title , :shop_id => a.id, :product_type => a.product_type)
#shop.save
rescue ActiveRecord::RecordNotUnique
redirect_to :action => "display_items"
end
end
#shop_items =Product.find(:all)
if session[:user_id]
#log = "Welcome Administrator!"
#logout="logout"
else
#log = "Admin Log in"
#logout=""
end
end
I'm having the error "uninitialized constant ActiveRecord::RecordNotUnique" when trying to save the data fed by the API. Any help would be appreciated. thank you.

Any reason why you use ActiveRecord 3.1 with Rails 2.3.4. Though it's possible to use that, it is not recommended.
ActiveRecord::RecordNotUnique is only available with versions 3.0 or higher. I am not sure if activerecord modules are initialized correctly with your version of Rails.

That error is returned when ActiveRecord tries to save a duplicate when the index says values need to be unique. In your case, the value Baby Ruth-49696852 is a duplication, and violates the uni_products key, which is set to be unique.
Either make the column not unique, or stop trying to save duplicate records. Did you create your database indexes in your migrations? Is there a :unique => true on any of the columns in your migrations?

Related

How to display results from database in Sinatra using Sequel?

I have an SQLite3 database called sk.db with a table called Sked that displays a schedule of sports matches with a column date. I am simply trying to display today's matches. It appears as though the connection to the database is not working, though I do not get any errors.
I have tried looking through the Sequel documentation to no avail. How can I display results from an existing database in Sinatra?
.rb
require 'date'
require 'sequel'
require 'sinatra'
DB = Sequel.connect("sqlite://sk.db")
class Sked < Sequel::Model
end
schedule = DB.from(:sked)
get '/' do
todaymatches = schedule.where(:date => Date.today)
erb :games
end
.erb
<h1>Games</h1>
<p><%= #todaymatches %></p>
.where doesn't actually retrieve data, but instead returns a dataset. Add an .all to actually retrieve the data
todaymatches = schedule.where(:date => Date.today).all

Can I change SQLite column name with DataMapper?

Brand new to DataMapper and wondering if I can use DataMapper.auto_updgrade! to change a column name of an existing column in a SQLite database?
If I have the following in a song.rb
require 'date'
require 'dm-core'
require 'dm-migrations'
DataMapper.setup(:default, "sqlite3://#{Dir.pwd}/development.db")
class Song
include DataMapper::Resource
property :id, Serial
property :title, String
property :music_by, String
property :lryics_by, String
property :lyrics, Text
property :length, Integer
property :released_on, Date
def released_on=date
super Date.strptime(date, '%m/%d/%Y')
end
end
DataMapper.finalize
After a Song.auto_migrate!
2.0.0-p598 :004 > Song.new
=> #<Song #id=nil #title=nil #music_by=nil #lyrics_by=nil #lyrics=nil #length=nil #released_on=nil>
Is it possible to change the
property :lryics_by, String
to
property :words_by, String
and have the database column name change, but keep any existing data?
I've tried with Song.auto_upgrade! and it adds an empty new column and leaves the original column and data in place. On the other hand, my Song.new object looks right.
2.0.0-p598 :004 > Song.new
=> #<Song #id=nil #title=nil #music_by=nil #words_by=nil #lyrics=nil #length=nil #released_on=nil>
It seems like I need a migration in the way that ActiveRecord (I've played around a little with that ORM) handles migrations. Or I would need to change the column name with SQL or an app or the Firefox SQLlite plugin.
UPDATE:
I'm wondering now if this is more a SQLite thing than a DataMapper thing. When I went to delete a column in Firefox's SQLite Manager plugin I got this message:
This is a potentially dangerous operation. SQLite does not support statements that can alter a column in a table. Here, we attempt to reconstruct the new CREATE SQL statement by looking at the pragma table_info which does not contain complete information about the structure of the existing table.
Do you still want to proceed?
dm-migrations can do this but not for SQLite, mostly because SQLite doesn't support renaming columns, as it has a limited ALTER TABLE implementation (http://www.sqlite.org/lang_altertable.html)
There's a rename_column migration but as you can see from the dm-migrations TableModifier class (https://github.com/datamapper/dm-migrations/blob/master/lib/dm-migrations/sql/table_modifier.rb), it's not available for SQLite:
def rename_column(name, new_name, opts = {})
# raise NotImplemented for SQLite3
#statements << #adapter.rename_column_type_statement(table_name, name, new_name)
end

Ruby Sequel, "insert ignore" returns undefined method?

Trying to do a multi_insert (or insert, for that matter) with the Sequel gem, using "insert_ignore". I get an undefined method error.
The table
DB = Sequel.connect('sqlite://database.db')
DB.create_table! :users do
primary_key :id
String :name, :default => nil, :unique => true
end
users = [{:name => 'bob'}, {:name => 'bob'}, {:name => 'mary'}]
DB[:users].insert_ignore.multi_insert(users)
this returns
undefined method "insert_ignore" for <#Sequel::SQLite::Dataset: "SELECT * FROM 'users'"> (NoMethodError)
what's wrong? Does SQLite3 not support insert_ignore statements?
confused!
Does SQLite3 not support insert_ignore statements? confused!
The Sequel docs for Sequel::MySQL::DatasetMethods, which are here:
http://sequel.jeremyevans.net/rdoc-adapters/classes/Sequel/MySQL/DatasetMethods.html#method-i-insert_ignore
list the method insert_ignore(), but the Sequel docs for Sequel::SQLite::Dataset, which are here:
http://rdoc.info/github/evanfarrar/opensprints/Sequel/SQLite/Dataset
do not list that method, and the fact that you are getting an undefined method error is pretty good evidence that Sequel does not implement insert_ignore() for sqlite.
However, according to the sqlite docs here:
http://sqlite.org/lang_conflict.html
sqlite does support INSERT OR IGNORE queries. So, if you want to use that functionality, it looks like you'll have to use raw sql with Sequel:
require 'sequel'
require 'sqlite3'
DB = Sequel.sqlite('mydb1.db')
DB.create_table! :users do
primary_key :id
String :name, :default => nil, :unique => true
end
#users = [{:name => 'bob'}, {:name => 'bob'}, {:name => 'mary'}]
my_insert =<<END_OF_QUERY
INSERT OR IGNORE INTO users(name) VALUES
('bob'),
('bob'),
('mary')
END_OF_QUERY
data_set = DB[my_insert]
data_set.insert
Your way worked, but I ended up doing something like:
record = DB[table.to_sym].where(data)
if 1 != record.update(data)
DB[table.to_sym].insert(data)
end
end
this way the record gets updated if it already exists
The sequel gem has now implemented SQLite support for Dataset#insert_ignore, released with version 4.30.0 on Jan 4 2016.
Upgrading to sequel >= 4.30.0 should solve this issue.

ActiveRecord is showing wrong column defaults

This is my first time using ActiveRecord in a non-rails application, and I'm running into a problem. ActiveRecord is able to figure out the columns I have in my sqlite3 database, but it can't figure out the default column values for some reason.
Here is the sql description for the table in question.
-- Describe ACCOUNTS
CREATE TABLE "accounts" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL DEFAULT (0),
"username" TEXT NOT NULL,
"password_hash" BLOB NOT NULL,
"creation_time" INTEGER NOT NULL DEFAULT(strftime('%s', 'now')),
"expiration_time" INTEGER NOT NULL DEFAULT(strftime('%s', 'now') + 2592000)
)
I used the following code for loading my database file.
require 'active_record'
require './config.rb'
ActiveRecord::Base.establish_connection(
:adapter => 'sqlite3',
:database => DB_FILE
)
class Account < ActiveRecord::Base
end
When I look at the column defaults for the Account table with a REPL, this is what I get:
[10] pry(main)> Account.column_defaults
=> {"id"=>0,
"username"=>nil,
"password_hash"=>nil,
"creation_time"=>0,
"expiration_time"=>0}
I worked with ActiveRecord for a rails app before and it was smart enough to figure out the default values. For some reason, it can't figure them out now.
Am I doing something wrong here? I read that I can manually specify the default value with default :id => bla, but shouldn't ActiveRecord be able to figure out the defaults?
Update: I think I figured out a workaround. The hash returned by Account.column_defaults is writeable, and changing those elements seems to work fine.
Try doing this:
class Account < ActiveRecord::Base
after_initialize :default_values
private
def default_values
self.username ||= "default value"
#etc...
end
end

Rails 3 Collection `sum` fails with TypeError

In a sample Rails 3.2.8 app (on Ruby 1.9.3) there is the following simple setup:
class Account < ActiveRecord::Base
has_many :line_items
def subtotal
line_items.sum(&:price)
end
end
class Line_Item < ActiveRecord::Base
belongs_to :product
def price
product.price * time
end
end
account = Account.new
account.line_items.build do |item|
item.years = 4
item.product = Product.last
end
account.subtotal
#=> TypeError: nil can't be coerced into BigDecimal
As above the subtotal method fails with a conversion error. In subtotal I checked the type returned by line_items.class and got Array. If I update the definition of subtotal to either of the following, the method works:
line_items.to_a.sum(&:price)
#=> #<BigDecimal:7ff4d34ca7c8,'0.0',9(36)>
line_items.map(&:price).sum
#=> #<BigDecimal:7ff4d3373b40,'0.0',9(36)>
Why does the initial definition of line_items.sum(&:price) fail?
This appears to be a bug in Rails (at least in 3.2.8).
In Rails 3.2.8, the has_many association is dynamically defining collection.sum.
Though this isn't reflected in A Guide to Active Record Associations
or ActiveRecord::Associations::ClassMethods API docs; it is briefly listed in the API under the "Collection associations (one-to-many / many-to-many)"
chart, but not referenced again.
According to the code, it will always try to hit the database using a SQL sum.
However, in this particular instance, the model isn't saved. So there's nothing
in the database.
So to clear that up a little:
account.line_items.sum(&:price) # Uses Collection#sum, goes to database
account.line_items.map.sum(&:price) # Uses Enumerable#map then Enumerable#sum
This has been logged under issue #7928; which appears related to issue #5215: "finders and scopes on has_many association on new object incorrectly query db for null foreign keys".

Resources