Active Record acting weird - ruby-on-rails

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

Related

On MySQL's character set "utf8mb4", even rails console runs well, but seed_fu doesn't runs well

On MySQL's character set "utf8mb4",
rails console runs well like this.
<pre>
<p style="background-color:#FFFFFF;border:1px solid #999999;padding:5px;">
10191% rails c -e production Loading production environment (Rails 4.2.5)
irb(main):001:0> skin = Skin.first
Skin Load (203.9ms) SELECT `skins`.* FROM `skins` ORDER BY `skins`.`id` ASC LIMIT 1
=> #<Skin id: 1, created_at: "2015-12-19 07:59:48", updated_at: "2015-12-19 08:08:34", name: "🌻", file: "standard.css", expression: "">
irb(main):002:0> skin.name = 'たのしい🌻''
irb(main):003:0'
irb(main):004:0' '
=> "たのしい🌻\n\n"
irb(main):005:0> skin.name = 'たのしい🌻'
=> "たのしい🌻"
irb(main):006:0> skin.save
(112.3ms) BEGIN
SQL (115.0ms) UPDATE `skins` SET `name` = 'たのしい🌻', `updated_at` = '2015-12-19 11:56:18' WHERE `skins`.`id` = 1
(105.7ms) COMMIT
=> true
</p>
</pre>
But "rake db:seed_fu" doesn't runs well like this.
<pre>
<p style="background-color:#FFFFFF;border:1px solid #999999;padding:5px;">
10192% rake db:seed_fu RAILS_ENV=production
== Seed from /Users/js/work/picrating/db/fixtures/production/publish.rb
- Publish {:id=>1, :name=>"公開"}
- Publish {:id=>2, :name=>"非公開"}
== Seed from /Users/js/work/picrating/db/fixtures/production/skin.rb
- Skin {:id=>1, :name=>"standard", :file=>"standard.css", :expression=>"レギュラー"}
- Skin {:id=>2, :name=>"light", :file=>"light.css", :expression=>"たのしい🌻"}
rake aborted!
ActiveRecord::StatementInvalid: Mysql2::Error: Incorrect string value: '\xF0\x9F\x8C\xBB' for column 'expression' at row 1: INSERT INTO `skins` (`id`, `name`, `file`, `expression`, `created_at`, `updated_at`) VALUES (2, 'light', 'light.css', 'たのしい🌻', '2015-12-19 12:08:05', '2015-12-19 12:08:05')
(eval):1:in `block (2 levels) in run_file'
Mysql2::Error: Incorrect string value: '\xF0\x9F\x8C\xBB' for column 'expression' at row 1
(eval):1:in `block (2 levels) in run_file'
Tasks: TOP => db:seed_fu
(See full trace by running task with --trace)
</p>
</pre>
I have no idea, that even rails console runs well,
but db:seed_fu doesn't run well.
What happened?
Is this a sufficient clue?
In application_controller.rb
def configure_charsets
response.headers["Content-Type"] = "text/html; charset=utf-8"
suppress(ActiveRecord::StatementInvalid) do
ActiveRecord::Base.connection.execute 'SET NAMES utf8mb4'
end
end

ruby / rails: TypeError: can't convert Symbol into Integer

I'm trying to update my Representation attributes ivpn & idirect (from a csv file via rake task but i just print here only the meat of the program) and getting the TypeError:
# in Rails Console:
representation = Representation.where(id: 977)
# => Representation_id: 977, ivnp: false, idirect: false
rows = Hash.[:ivpn => "", :idirect => "x"] # originally rows are coming from csv-file
representation.update_attributes! ivpn: rows.any?{|r| r[:ivpn].present?}, idirect: rows.any? {|r| r[:idirect].present?}
TypeError: can't convert Symbol into Integer
from (irb):42:in `[]'
from (irb):42:in `block in irb_binding'
from (irb):42:in `each'
from (irb):42:in `any?'
What I'm missing here?
try this:
representation.update_attributes! ivpn: rows.any?[{|r| r[:ivpn].present?}], idirect: rows.any? [{|r| r[:idirect].present?}]

How to monkey patch Commontator::Comment (or any rails engine)?

I just recently learned the term monkey patching, so I'm not sure if I have it right.
I am using the Commontator gem to provide commenting functionality on my Blog (Monologue::Post models) and my other models. I ran into an issue where I was trying to get the parent object from my comment (ie, what was commented on). It looks like I would have to do three joins. Rather than call that in my controller, I thought I could extend the gem's model to have a function comment_parent that would return the parent model.
I have this:
# config/initializers/comment_model_extenders.rb
module Commontator
class Comment < ActiveRecord::Base
def comment_parent
# do some magic
"return parent here"
end
end
end
I must be doing it wrong, because I am getting this error:
irb(main):010:0> c=Commontator::Comment
=> Commontator::Comment(id: integer, creator_type: string, creator_id: integer, editor_type: string, editor_id: integer, thread_id: integer, body: text, deleted_at: datetime, cached_votes_up: integer, cached_votes_down:
integer, created_at: datetime, updated_at: datetime)
irb(main):011:0> c.comment_parent
NoMethodError: undefined method `comment_parent' for #<Class:0xab743d0>
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/dynamic_matchers.rb:26:in `method_missing'
from (irb):11
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/console.rb:90:in `start'
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/console.rb:9:in `start'
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/commands_tasks.rb:69:in `console'
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/commands_tasks.rb:40:in `run_command!'
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands.rb:17:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
EDIT:
Based off of Fredrick's comments, I changed my code to be
...
def self.comment_parent
...
but the output is as follows:
irb(main):022:0* c=Commontator::Comment
=> Commontator::Comment(id: integer, creator_type: string, creator_id: integer, editor_type: string, editor_id: integer, thread_id: integer, body: text, deleted_at: datetime, cached_votes_up: integer, cached_votes_down:
integer, created_at: datetime, updated_at: datetime)
irb(main):023:0> c.comment_parent
=> "return parent here"
irb(main):024:0> test = c.find(1)
Commontator::Comment Load (35.7ms) SELECT "commontator_comments".* FROM "commontator_comments" WHERE "commontator_comments"."id" = $1 LIMIT 1 [["id", 1]]
=> #<Commontator::Comment id: 1, creator_type: "User", creator_id: 2, editor_type: nil, editor_id: nil, thread_id: 2, body: "Love this parser.", deleted_at: nil, cached_votes_up: 0, cached_votes_down: 0, created_at: "201
5-02-12 22:04:48", updated_at: "2015-02-12 22:04:48">
irb(main):025:0> test.comment_parent
NoMethodError: undefined method `comment_parent' for #<Commontator::Comment:0xad08a10>
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/activemodel-4.1.8/lib/active_model/attribute_methods.rb:435:in `method_missing'
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/attribute_methods.rb:213:in `method_missing'
from (irb):25
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/console.rb:90:in `start'
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/console.rb:9:in `start'
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/commands_tasks.rb:69:in `console'
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/commands_tasks.rb:40:in `run_command!'
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands.rb:17:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
Looking at the library, your parent object has_one :thread, :as => :commontable, while the thread has_many :comments.
So, inside a Comment, thread.commontable should get you the other way around back up to your original parent.
Based on the comments, here is my solution:
In general, I wanted it to be called as an instance method, so my original code was correct. I was just calling it wrong. To call an instance method, do one of these:
Model.new.custom_method
or
my_model = Model.new #or .find(n)
my_model.custom_method
For my specific case, I found this solution:
module Commontator
class Comment < ActiveRecord::Base
def comment_parent
# do some magic
thread = Commontator::Thread.find(self.thread_id)
parent_class = thread.commontable_type.camelize.constantize
parent_class.find(thread.commontable_id)
end
end
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.

Rails Active Record ID vs. Object ID + Active::Relation

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

Resources