why can't I use create_or_update? - ruby

It's unclear to me why this isn't working:
class FastGrowers < ActiveRecord::Base
end
FastGrowers.create_or_update(:id => t.id, :ticker => ticker, :five_year_growth_rate => growth_rate)
I get this as a result:
/var/lib/gems/1.9.1/gems/activerecord-3.2.13/lib/active_record/dynamic_matchers.rb:55:in `method_missing': undefined method `create_or_update' for #<Class:0x8aaa264> (NoMethodError)
what gives?

It's not working because that method is not provided by ActiveRecord.
Perhaps you want FastGrowers.find_or_create_by_id?
grower = FastGrowers.find_or_create_by_id(t.id)
grower.update_attributes(:ticker => ticker, :five_year_growth_rate => growth_rate)
But if you have an id, you should know if you have a record, right? Hard to tell what you are trying to do, but something there is fishy.

Related

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.

Undefined method `[]' for nil:NilClass when trying to pull value from hash

I'm new to Ruby, and for the most part it's starting to make sense, but then I came across this problem.
I searched for a user using:
user = User.find_by_id(user_id)
I can do user.inspect and it displays as:
#<User id: 1, username: "test_user", first_name: "test", last_name: "user">
However, when I try to do:
user[:id]
I get:
undefined method `[]' for nil:NilClass
What am I overlooking?
Here is the user.rb:
class User < ActiveRecord::Base
# Validations
validates :first_name, :last_name, :presence => true
validates :username, :uniqueness => {:allow_blank => true}
# Setup accessible (or protected) attributes for your model
default_fields = [:username, :first_name, :last_name]
attr_accessible *default_fields
# Instance Methods
def full_name
"#{first_name} #{last_name}"
end
end
Additionally, if I do:
user.to_s
it results in:
#<User:0x007fdad09717f8>
Which further leads me to believe that it's not nil, but yet I can't reference the hash values.
your first sentence
user = User.find_by_id(user_id)
returned a null object, so you need to test this in order to avoid the exception:
if( ! user.nil? )
# code with user[:id]
end
So the problem turns out not to be related to code, but to data in a Database table that I was using to get the 'user_id' value. Thats what I get for trusting that someone else would have written proper validations on all the models in the project.
Thats everyone for helping me resolve this, if I hadn't needed to create a minimum example that reproduced the issue I never would have stumbled across the bad entry in the database.
So to use Miguel Prz's Idea I ended up doing this:
user.nil? ? '' : user[:id]
This is further proof why I should never trust anyone else's work :)

Why is the stubbed method not called?

It seems I understood something wrong. I have a class
module Spree
class OmnikassaPaymentResponse
#...
# Finds a payment with provided parameters trough ActiveRecord.
def payment(state = :processing)
Spree::Payment.find(:first, :conditions => { :amount => #amount, :order_id => #order_id, :state => state } ) || raise(ActiveRecord::RecordNotFound)
end
end
end
Which is specced in Rspec:
describe "#payment" do
it 'should try to find a Spree::Payment' do
Spree::Payment.any_instance.stub(:find).and_return(Spree::Payment.new)
Spree::Payment.any_instance.should_receive(:find)
Spree::OmnikassaPaymentResponse.new(#seal, #data).payment
end
end
This, however, always throws ActiveRecord::RecordNotFound. I expected any_instance.stub(:find).and_return() to make sure that whenever, wherever I call a #find on whatever instance I happen to have of Spree::Payment, it returns something.
In other words: I would expect the stub.and_return would avoid getting to || raise(ActiveRecord::RecordNotFound). But it does not.
Is my assumption wrong, my code? Something else?
In your case find is not an instance method, but a class method of Spree::Payment. That means you should stub it directly without any_instance like that:
Spree::Payment.stub(:find).and_return(Spree::Payment.new)

LoadError - Expected to define. Rails error when calling module

I have a module called EntityTrackerHelper. Here is the code:
module EntityTrackerHelper
def self.createUserAction(user_id, type, entity_id)
existingua = UserAction.find(:first, :conditions=> ["user_id = ? and type = ? and entity_id=?", user_id, type, entity_id])
if existingua.nil?
ua = UserAction.new
ua.user_id = user_id
ua.type = type
ua.entity_id = entity_id
ua.date = Time.now
ua.save
else
existingua.date = Time.now
existingua.save
end
end
end
It is used to track changes and user access in an entity.
It is used in a controller as follows.
require "#{Rails.root}/lib/EntityTrackerHelper"
class LessonSectionsController < InheritedResources::Base
def index
user_id = params[:user_id]
lesson_id = params[:lesson_id]
EntityTrackerHelper::createUserAction(user_id, 'LESSON', lesson_id)
lessonSections = LessonSection.find(:all, :conditions => { :lesson_id => params[:lesson_id] })
render :json => {:sections => lessonSections.as_json({:only => [:lesson_id,:id,:name]}), :error => ''}
end
end
I get the following error:
LoadError (Expected /<ProjPath>/<ProjName>/app/models/lesson.rb to define LESSON):
lib/EntityTrackerHelper.rb:12:in `createUserAction'
app/controllers/lesson_sections_controller.rb:9:in `index'
Line 12 in EntityTrackerHelper is UserAction.find...
Any idea?
Thanks
ActiveRecord will use the field type for "single table inheritance". See http://api.rubyonrails.org/classes/ActiveRecord/Base.html (subtitle: single table inheritance).
It means that when it loads the UserAction with type LESSON, ActiveRecord will try to instantiate the class LESSON which is not defined.
You probably should use another name for your type column.
You can try using
**include EntityTrackerHelper**
for more info check this link Call Module function from Controller (NoMethodError)

Ruby on Rails & Calling methods with Symbols Basic Question

For some reason I haven't quite gotten the hang of how Rails interacts with Ruby / figured out Ruby itself.
I'll get to the point. For example in a Ruby on Rails project you might have something like this:
class Product < ActiveRecord::Base
default_scope :order => 'title'
end
This confuses the crap out of me. I assume we are calling the method default_scope which Product inherits from the base ActiveRecord class... so that we can set some options. We pass it the symbol :order => 'title'. is :order just a hash value within the default_scope function and it is setting that hash value as 'title' ? Am I getting that correctly.
Also for example, when you start to throw basic validation in you get something like this
validates :price, :numericalcity => {:greater_than_or_equal_to => 0.01 }
I know what this does but its syntax blows my mind. First it looks like symbols are used for static reused string values, but here we are sending in a dynamic symbol in... where is that going? And then are we a symbol within a symbol? Is that basically a hash within a hash or what exactly is it doing? I'm just trying to trace it out within my brain to actually understand what is going on.
You are correct in assuming default_scope being a method, which is inherited from ActiveRecord::Base. Go here to view the source code of default_scope.
It is a method which takes an optional Hash as it's only parameter.
This,
default_scope :order => 'title'
is the same as writing it as,
default_scope( { :order => 'title' } )
In ruby if a method is defined like,
def foobar(options = {})
p options
end
But beware of a subtle difference in syntax. Above, if you leave out the () keeping the {} ruby understands it as something entirely different. Ruby sees a method default_scope which accepts a code block as it's argument.
default_scope { # code block }
This method definition will look like,
def foobar(&block)
yield
end
To understand how ruby blocks work read this.
You can call it like,
foobar :key_1 => 'value_1', "key_2" => 'value_2'
And Ruby understands it to be,
foobar( { :key_1 => 'value_1', "key_2" => 'value_2' } )
The keys of the Hash may or may not be symbols.
As for the validation helper method for the column attribute price,
validates :price, :numericality => { :greater_than_or_equal_to => 0.01 }
Is the same as,
validates( :price, { :numericality => { :greater_than_or_equal_to => 0.01 } } )
This is similar to a method definition like,
def validates(column_attr, options = {})
# perform validation of column_attr
end
default_scope :order => 'title'
Is a method call
default_scope( {:order => 'title'} )
Ruby allows you to omit parentheses and braces in this case.
validates :price, :numericalcity => {:greater_than_or_equal_to => 0.01 }
means
validates( :price, {:numericalcity => {:greater_than_or_equal_to => 0.01 } } )

Resources