Ruby Sequel, "insert ignore" returns undefined method? - ruby

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.

Related

Activerecord returning all results as a hash

I have the following connecting to a db called dbblah and table1(names changed)
require 'active_record'
ActiveRecord::Base.establish_connection(
:adapter => "mysql",
:host => "192.168.1.10",
:database => "automation",
:username => "root",
:password => "password"
)
ActiveRecord::Base.pluralize_table_names = false
class Table1 < ActiveRecord::Base
end
db = Table1.find_by(db: 'dbname')
puts db
But when I run it, I am getting the results as a hash it looks like:
[root#localhost server]# ruby blah.rb
#<Table1:0x000000019796a8>
This is just the output of to_s method called on a new object - it is definitively not a hash. By default when calling puts method with a non-string, to_s method is called on that object to display a string. For ActiveRecord models to_s method results in exactely what you got.
Try calling p db to display result of method inspect called on that object, which will give you more insight in its internal structure.

ActiveRecord and sqlite3 : find does not accept any condition?

I have a problem I can't figure out here. I'm writing a ruby script that deals with an sqllite database.
require 'rubygems'
require 'sqlite3'
require 'active_record'
ActiveRecord::Base.establish_connection(
:adapter => "sqlite3",
:database => "../database/my.db"
)
class KeyWord < ActiveRecord::Base
set_table_name "keywords"
end
# THIS STATEMENT WORKS (finds the first record, returns "ruby") :
KeyWord.find(1).keyval
# THOSE STATEMENTS RETURN NO RESULT :
KeyWord.find(:all, :conditions => {:keyval => "ruby"})
KeyWord.find_by_sql("SELECT * FROM keywords WHERE keyval='ruby'")
KeyWord.find_by_keyval("ruby")
This is how the table was created :
create_table :keywords do |table|
table.column :keyval, :text
end
Does anyone know where this could come from ?
Thanks,
R.
I see a couple of issues here.
I'm not sure why you're manually setting your table name.
ActiveRecord assumes that your model name is camelCased. So... AR
would, by default, search for a table called key_words. Why not just
go with that?
Pay attention to which version of active record you are
using. Passing in conditions is deprecated. You should be using the
.where syntax. So... you would need to do KeyWord.where(:keyval
=> 'ruby').first or end in .all for a collection of results.
If you are just fooling around, you can use sqlite3 in memory.
ActiveRecord::Base.establish_connection( adapter: 'sqlite3',
database: ":memory:")
Also don't forget to define your schema!
Here is full code w/ more modern syntax.
require 'rubygems'
require 'sqlite3'
require 'active_record'
ActiveRecord::Base.establish_connection( adapter: 'sqlite3', database: ":memory:" )
ActiveRecord::Migration.verbose = false
ActiveRecord::Schema.define(version: 2) do
create_table :key_words do |t|
t.text :keyval
end
end
class KeyWord < ActiveRecord::Base
end
Keyword.create!(:keyval => 'ruby')
# THESE STATEMENTS WORK:
KeyWord.find(1).keyval
KeyWord.where(:keyval => 'ruby').first
KeyWord.where(:keyval => 'ruby').all
KeyWord.find_by_sql("SELECT * FROM key_words WHERE keyval='ruby'")
KeyWord.find_by_keyval("ruby")

uninitialized constant ActiveRecord::RecordNotUnique

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?

Pony and Sequel associations conflict?

I've run into an issue when using Pony and Sequel in a Sinatra application.
Without Pony everything goes just fine, but just requiring Pony sequel's associations break.
Here's my models for a blog:
class Post < Sequel::Model
one_to_many :comments, :order => :date.asc(), :conditions => {:approved => 1}
set_schema do
primary_key :id
varchar :title
varchar :text
varchar :category
varchar :status
datetime :date
varchar :link
end
end
class Comment < Sequel::Model
plugin :validation_helpers
many_to_one :posts
attr_accessor :ip, :user_agent, :referrer, :permalink
set_schema do
primary_key :id
integer :post_id
varchar :author
varchar :comment
DateTime :date
varchar :email
varchar :url
varchar :approved
end
Then I call them like this in a route
post '/:link' do
#post = Post[:link=>params[:link]]
params[:comment].merge!( {
:ip => request.ip.to_s,
:user_agent => request.env['HTTP_USER_AGENT'].to_s,
:referrer => request.env['REFERER'].to_s,
:permalink => request.env['REFERER'].to_s
} )
begin
#comment = Comment.create params[:comment]
#post.add_comment #comment
rescue
#message = $!
end
#title = #post.title
haml :posts
end
I don't even have to call pony somewhere, just requiring it #post.add_comment #comment fails. It says
NoMethodError - undefined method `_add_comments' for #<Post:0x102b09890>:
/Library/Ruby/Gems/1.8/gems/sequel-3.21.0/lib/sequel/model/associations.rb:1078:in `send'
/Library/Ruby/Gems/1.8/gems/sequel-3.21.0/lib/sequel/model/associations.rb:1078:in `add_associated_object'
/Library/Ruby/Gems/1.8/gems/sequel-3.21.0/lib/sequel/model/associations.rb:743:in `add_comment'
Seems to me like a conflict with send? I don't even know how to start to debug it.
This is caused by an ActiveSupport issue, believe it or not. You should drop down to ActiveSupport 3.0.3 or manually require the default ActiveSupport inflections via:
require 'active_support/inflections'
Basically, after 3.0.3, ActiveSupport made it possible to load the inflector without the default inflections, which results in broken singularize and pluralize methods. The mail gem, which I'm guessing pony uses, is one of libraries that is known to be broken by this change.
The Rails developers apparently do not consider this a bug in ActiveSupport, but a bug in the libraries that use ActiveSupport.

ActiveRecord/sqlite3 column type lost in table view?

I have the following ActiveRecord testcase that mimics my problem. I have a People table with one attribute being a date. I create a view over that table adding one column which is just that date plus 20 minutes:
#!/usr/bin/env ruby
%w|pp rubygems active_record irb active_support date|.each {|lib| require lib}
ActiveRecord::Base.establish_connection(
:adapter => "sqlite3",
:database => "test.db"
)
ActiveRecord::Schema.define do
create_table :people, :force => true do |t|
t.column :name, :string
t.column :born_at, :datetime
end
execute "create view clowns as select p.name, p.born_at, datetime(p.born_at, '+' || '20' || ' minutes') as twenty_after_born_at from people p;"
end
class Person < ActiveRecord::Base
validates_presence_of :name
end
class Clown < ActiveRecord::Base
end
Person.create(:name => "John", :born_at => DateTime.now)
pp Person.all.first.born_at.class
pp Clown.all.first.born_at.class
pp Clown.all.first.twenty_after_born_at.class
The problem is, the output is
Time
Time
String
When I expect the new datetime attribute of the view to be also a Time or DateTime in the ruby world. Any ideas?
I also tried:
create view clowns as select p.name, p.born_at, CAST(datetime(p.born_at, '+' || '20' || ' minutes') as datetime) as twenty_after_born_at from people p;
With the same result.
Well, after more investigation, I found that:
MySQL works:
%w|pp rubygems active_record irb active_support date|.each {|lib| require lib}
ActiveRecord::Base.establish_connection(
:adapter => "mysql",
:username => "root",
:database => "test2"
)
ActiveRecord::Schema.define do
create_table :people, :force => true do |t|
t.column :name, :string
t.column :born_at, :datetime
end
execute "create view clowns as select p.name, p.born_at, (p.born_at + INTERVAL 20 MINUTE) as twenty_after_born_at from people p;"
end
class Person < ActiveRecord::Base
validates_presence_of :name
end
class Clown < ActiveRecord::Base
end
Person.create(:name => "John", :born_at => DateTime.now)
pp Person.all.first.born_at.class
pp Clown.all.first.born_at.class
pp Clown.all.first.twenty_after_born_at.class
Produces:
Time
Time
Time
Reading the sqlite3 adapter source code, I found out that it uses PRAGMA table_info(table_name) to get the type information, and that does not return the types for views:
sqlite> pragma table_info('people');
0|id|INTEGER|1||1
1|name|varchar(255)|0||0
2|born_at|datetime|0||0
sqlite> pragma table_info('clowns');
0|name|varchar(255)|0||0
1|born_at|datetime|0||0
2|twenty_after_born_at||0||0
Therefore it may be a limitation of the adapter or just a sqlite3's views limitation. I have opened a ticket for ActiveRecord:
Also, quoting this mail in sqlite-users:
RoR should be using the
sqlite3_column_type() API to determine
the type of the values returned from a
query. Other APIs like
sqlite3_column_decltype() and pragma
table_info are returning other
information, not the type of the
result value.
Well, basically there is no datatime type in SQLite as opposed to MySQL. In your example you explicitly define types for the table but do not specify types for the view. That might be the problem. Can not check it since I have never touched ruby.

Resources