Rails Active Record ID vs. Object ID + Active::Relation - ruby-on-rails

I've been receiving messages like this:
warning: Object#id will be deprecated; use Object#object_id
I read and attempted the tricks from Ruby Object#id warnings and Active Record without success:
108-125-94-123:toptickets johnnygoodman$ rails c
Loading development environment (Rails 3.0.3)
>> ticket_id = 8899
=> 8899
>> ticket = Ticket.where(:number => ticket_id)
=> [#<Ticket id: 97, name: "Set Up API to Feed Customer Info into Bronto ", number: "8899", category_id: 15, created_at: "2011-01-31 21:24:29", updated_at: "2011-01-31 21:24:29", position: 20>]
>> ticket.id
(irb):3: warning: Object#id will be deprecated; use Object#object_id
=> 2175680980
>> ticket[:id]
TypeError: Symbol as array index
from /Library/Ruby/Gems/1.8/gems/activerecord-3.0.3/lib/active_record/relation.rb:363:in `[]'
from /Library/Ruby/Gems/1.8/gems/activerecord-3.0.3/lib/active_record/relation.rb:363:in `send'
from /Library/Ruby/Gems/1.8/gems/activerecord-3.0.3/lib/active_record/relation.rb:363:in `method_missing'
from (irb):4
>> ticket.class
=> ActiveRecord::Relation
I'd expect that when I queried for ticket it would be of class ActiveRecord::Base. I'm not sure what to do to get that going or if its the direction I should head in.
Goal: Query for a ticket, print its id. In the example above, the id's value should be 97.

ticket = Ticket.where(:number => ticket_id) returns an ActiveRecord::Relation (which when evaluated in IRB, performs the database query and returns an array of tickets). So ticket.id is trying to perform .id on the entire array of tickets, not one actual ticket.
Maybe you only want the first result?
>> ticket = Ticket.where(:number => ticket_id).first
>> puts ticket.id
=> 97

Related

Active Record acting weird

Question am I doing something wrong with the following code?
Controller Test
irb(main):003:0> x = Notations.all.first
/Users/programmer/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-sqlserver-adapter-4.2.18/lib/active_record/connection_adapters/sqlserver/database_statements.rb:354: warning: :timezone option must be :utc or :local - defaulting to :local
Notations Load (1.8ms) EXEC sp_executesql N'SELECT [notation].* FROM [notation]'
=> #<ActiveRecord::Relation [#<Notations ROWID: 1, TYPE: "Q ", OWNER_ID: "00003", CREATE_DATE: "2017-05-31 21:32:06", NOTE: "\r\x00\n\x00R\x00e\x00f\x00e\x00r\x00e\x00n\x00c\x00e\x00 \x00R\x00F\x00Q\x00 \x001\x007\x005\x005\x002\x00-\x000\x001\x000\x00...">]
The above works and retrieves my row that I queried for.
but below I tried to get the data for x.owner_id from the above and it fails(which clearly owner_id is a column in the returned query above)
irb(main):005:0> x.owner_id
NoMethodError: undefined method `owner_id' for #<Notations::ActiveRecord_Relation:0x007fb83cecf288>
from /Users/programmer/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-4.2.8/lib/active_record/relation/delegation.rb:136:in `method_missing'
from /Users/programmer/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-4.2.8/lib/active_record/relation/delegation.rb:99:in `method_missing'
from (irb):5
from /Users/programmer/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.2.8/lib/rails/commands/console.rb:110:in `start'
from /Users/programmer/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.2.8/lib/rails/commands/console.rb:9:in `start'
from /Users/programmer/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.2.8/lib/rails/commands/commands_tasks.rb:68:in `console'
from /Users/programmer/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.2.8/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
from /Users/programmer/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.2.8/lib/rails/commands.rb:17:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
I found the problem. The column names of the db were uppercase, so:
y = x.owner_id # failure
y = x.OWNER_ID # success
irb(main):004:0> x.OWNER_ID
=> "00003"
Solution:
Using an initializer to use lowercase schema reflection:
ActiveRecord::ConnectionAdapters::SQLServerAdapter.lowercase_schema_reflection = true
So now:
x = Notations.all.first
irb(main):002:0> x = Notations.all.first
/Users/programmer/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-sqlserver-adapter-4.2.18/lib/active_record/connection_adapters/sqlserver/database_statements.rb:354: warning: :timezone option must be :utc or :local - defaulting to :local
Notations Load (1.9ms) EXEC sp_executesql N'SELECT [notation].* FROM [notation] ORDER BY [notation].[owner_id] ASC OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY'
irb(main):003:0> x.owner_id
=> "00003"
irb(main):004:0>
As you can see above adding the initializer worked it changed the columns to lower case. I agree with having my columns lower case in the first place. However I am unable to change them due to this DB is used with my company's ERP system
You are calling the attribute on ActiveRecord::Relation whereas you must be calling it on Notations instance
x = Notations.all
#<ActiveRecord::Relation [#<Notations ROWID: 1, TYPE: "Q ", OWNER_ID: "00003", CREATE_DATE: "2017-05-31 21:32:06", NOTE: "\r\x00\n\x00R\x00e\x00f\x00e\x00r\x00e\x00n\x00c\x00e\x00 \x00R\x00F\x00Q\x00 \x001\x007\x005\x005\x002\x00-\x000\x001\x000\x00...">]
notation = x.first
#<Notations ROWID: 1, TYPE: "Q ", OWNER_ID: "00003", CREATE_DATE: "2017-05-31 21:32:06", NOTE: "\r\x00\n\x00R\x00e\x00f\x00e\x00r\x00e\x00n\x00c\x00e\x00 \x00R\x00F\x00Q\x00 \x001\x007\x005\x005\x002\x00-\x000\x001\x000\x00...">
notation.owner_id
#=> "00003"
NOTE: Whereas the above code must be working for you I will suggest few changes as per the ruby standard
Model name must be singular Notation instead of Notations
column names must be in lowercase owner_id instead of OWNER_ID

Method to list of attributes of a model which establishes a DB connection

In old Rails versions one could call a Model by name in the console and get a list of all attributes. In the new versions that is not possible - at least not right away until a connection is established:
$ rails c
Loading development environment (Rails 4.2.1)
>> Product
=> Product (call 'Product.connection' to establish a connection)
>>
I know that this is a feature and not a bug. And I know that a simple Product.count would establish the connection. I'm wondering what other method I could call to receive the list of attributes that automatically establishes the connection to the database. I'm looking for this output:
=> Product(id: integer, name: string, created_at: datetime, updated_at: datetime)
You can use column_names wich returns an Array of Model columns as string like :
$ rails c
Loading development environment (Rails 4.2.1)
>> Product.column_names
=> ["id", "name", "created_at", "updated_at"]
>>
or columns_hash which returns more informations
In your config/application.rb you can establish the connection like so:
console do
ActiveRecord::Base.connection
end

How to solve the method missing error in rails console

I've a model Dish and PriceDeal as follows
class Dish < ActiveRecord::Base
has_one :price_deal
end
class Dish < ActiveRecord::Base
belongs_to :dish
end
In rails console, I want to retrive the discountPercent value like this.
1.9.2p290 :130 > pd=PriceDeal.find(17)
=> #<PriceDeal id: 17, name: "deal1", description: "my deal1", discountPercent: 20.0, discountCash: nil, dish_id: 2, created_at: "2012-03-22 07:42:08", updated_at: "2012-04-16 11:16:49">
1.9.2p290 :131 > pd.discountPercent
=> 20.0
I got the expected result.
But when I try to get the value like this,
1.9.2p290 :132 > pd1 = PriceDeal.where(:dish_id => 2)
=> [#<PriceDeal id: 17, name: "deal1", description: "my deal1", discountPercent: 20.0, discountCash: nil, dish_id: 2, created_at: "2012-03-22 07:42:08", updated_at: "2012-04-16 11:16:49">]
1.9.2p290 :133 > pd1.discountPercent
NoMethodError: undefined method `discountPercent' for #<ActiveRecord::Relation:0xa134958>
from /home/ragunathjawahar/.rvm/gems/ruby-1.9.2-p290#rails3tutorial/gems/activerecord-3.0.11/lib/active_record/relation.rb:374:in `method_missing'
from (irb):133
from /home/ragunathjawahar/.rvm/gems/ruby-1.9.2-p290#rails3tutorial/gems/railties-3.0.11/lib/rails/commands/console.rb:44:in `start'
from /home/ragunathjawahar/.rvm/gems/ruby-1.9.2-p290#rails3tutorial/gems/railties-3.0.11/lib/rails/commands/console.rb:8:in `start'
from /home/ragunathjawahar/.rvm/gems/ruby-1.9.2-p290#rails3tutorial/gems/railties-3.0.11/lib/rails/commands.rb:23:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
I got error,
How to get the value of discountPercent from pd1.
Thanks.
The reason why this is happening is because when you use where, you get back not a single object of type PriceDeal, but you get an object of type ActiveRecord::Relation, which for all intents and purposes is an array.
Notice how you got:
[#<PriceDeal id: 17, name: "deal1", ... >]
Instead of just:
#<PriceDeal id: 17, name: "deal1", ... >
The braces ([]) mean that it's an array. So you'll have to do this:
pd1.first.discountPercent
The reason why the where method returns an array is because you can have multiple items returned. Imagine doing:
PriceDeal.where("discountPercent >= 0")
You'd probably get a lot of records from that.
pd=PriceDeal.find(17)
It will return only one particular column.so you will not get no method error.
when you are using Modelname.where("conditions").The results will be array.so you will get no method error.Because your method is not present to array.

Strange problem with activerecord fetch/find with column name 'changes' in a RAILS 2.3.8 model

How is this possible?
Loading development environment (Rails 2.3.8)
>> wq = Wq.first(:conditions =>['widget_id=? AND qs_id=?',1,1])
=> #<Wq id: 1, widget_id: 1, qs_id: 1, operator: 0, requirements: "2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2", changes: "1", route: 2, created_at: "2010-09-07 08:11:05", updated_at: "2010-11-24 10:25:53", body: "Which specific area of gyt are you aiming to addres...", options: "['xyz','pqr']", input_type: nil, status: 1>
>> wq.changes
=> {}
>> wq.changes
=> {}
>> wq.requirements
=> "2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2"
>> wq.changes
=> "1"
Why is wq.changes coming as null initially and then after logging wq.requirements, wq.changes seems to come fine?
All necessary fields that are being fetched are withing a attr_accessible in the model.
I am not able to understand this situation, please help all you rails gurus.
The attribute name 'changes' conflicts with the AR::Dirty functionality. You should probably pick a different name for that column.
Here's the rails3 api docs for Dirty:
http://api.rubyonrails.org/classes/ActiveModel/Dirty.html
In rails2 it's in ActiveRecord rather than ActiveModel.
If you aren't able to rename the column, you could work around the issue by calling #model_obj[:changes] instead.
https://github.com/rails/rails/blob/master/activerecord/lib/active_record/base.rb#L1466

MongoMapper - Updating existing records with new keys

When adding a key to an existing model (with existing data) via MongoMapper, I can create new documents with the new key but when trying to access existing documents using that same key it fails stating that it's an "undefined method."
I was wondering if anyone had any insight.
Thanks in advance!
(Yes, these examples are truncated.)
- model.rb -
key :key_1
key :key_2
- would return -
#<Model _id: BSON::ObjectID('4ba821abebddb9094c000001'), key_1: "test", key_2: "test">
- model.rb (updated version) -
key :key_1
key :key_2
key :key_3
- would still only return -
#<Model _id: BSON::ObjectID('4ba821abebddb9094c000001'), key_1: "test", key_2: "test">
- but if a new doc is created -
#<Model _id: BSON::ObjectID('4ba821abebddb9094c000001'), key_1: "test", key_2: "test">
#<Model _id: BSON::ObjectID('7ba131abedaab9094c007482'), key_1: "test", key_2: "test", key_3: "test">
This would be fine except for the fact that I receive a method undefined error when trying to access :key_3 for the first document.
Rails 2.3.4
MongoMapper 0.7.4
I'm not seeing this behavior at all, even when interacting with an object instantiated before I updated the class. When running the following in irb, I have no errors:
>> gem 'mongo_mapper', '0.7.4'
=> true
>> require 'mongo_mapper'
=> true
>> MongoMapper.database = 'test'
=> "test"
>> class Foo
>> include MongoMapper::Document
>> key :something
>> end
=> #<MongoMapper::Plugins::Keys::Key:0x101f8f938 #default_value=nil, #type=nil, #name="something", #options={}>
>> f = Foo.new(:something => 'thing')
=> #<Foo _id: ObjectID('4c4dc9af712337447c000001'), something: "thing">
>> f.save
=> true
>> f
=> #<Foo _id: ObjectID('4c4dc9af712337447c000001'), something: "thing">
>> class Foo
>> key :something_else
>> end
=> #<MongoMapper::Plugins::Keys::Key:0x101f6ad90 #default_value=nil, #type=nil, #name="something_else", #options={}>
>> f
=> #<Foo something_else: nil, _id: ObjectID('4c4dc9af712337447c000001'), something: "thing">
>> f.something_else
=> nil
Since it seems like you're having an unusual problem, more details of your use-case would be helpful. Could you please give us a more complete code example? If you've got proprietary stuff in the code that's failing, pare it down to the minimum case required to still have it fail and post the complete declarations of your models and the code you're using to access them.
Use the set command...
#model.set(:key_3 => "VALUE...")
#model.reload
#model.key_3 # => "VALUE..."
#model.save
This code will create a new field for your model, confirm that you already did defined with the new key:
key :key_3
Enjoy,

Resources