Could not find_by an object from database in Rails job - ruby-on-rails

I have created a Ruby on Rails job (extending from ActiveJob::Base) that parses a CSV file and inserts its rows as records (Students) in a database. That is working as expected.
However, when I try to fetch another object from the DB (the Career for each Student, which is part of each CSV row as a pair (career_code, career_name)), I'm getting this error:
undefined method 'find_by' for Career:Class
(I have also tried using Career.where instead).
I find this quite strange, since I'm already saving my Student, which is also an ActiveRecord::Base child class.
Here's the relevant part of my job:
ActiveRecord::Base.transaction do
student_hash.keys.each do |k|
some_student = student_hash[k]
student = Student.new
student.csv_id = some_student.id
student.first_name = some_student.first_name
student.last_name = some_student.last_name
student.file_number = some_student.file_number
# student.career = Career.where(code: some_student.career_code)
student.career = Career.find_by code: some_student.career_code
puts student.save! # Why this works, and the above line doesn't?
end
end
And also, the desired output, as I can see it in the Rails console:
Loading development environment (Rails 4.2.4.rc1)
2.1.3 :001 > Career.where(code: 11)
Career Load (0.5ms) SELECT "careers".* FROM "careers" WHERE "careers"."code" = ? [["code", 11]]
=> #<ActiveRecord::Relation [#<Career id: 4, name: "Informática", created_at: "2015-09-30 22:05:07", updated_at: "2015-09-30 22:05:07", code: 11>]>
2.1.3 :002 > Career.where code: 11
Career Load (0.2ms) SELECT "careers".* FROM "careers" WHERE "careers"."code" = ? [["code", 11]]
=> #<ActiveRecord::Relation [#<Career id: 4, name: "Informática", created_at: "2015-09-30 22:05:07", updated_at: "2015-09-30 22:05:07", code: 11>]>
2.1.3 :003 > Career.find_by code: 11
Career Load (0.4ms) SELECT "careers".* FROM "careers" WHERE "careers"."code" = ? LIMIT 1 [["code", 11]]
=> #<Career id: 4, name: "Informática", created_at: "2015-09-30 22:05:07", updated_at: "2015-09-30 22:05:07", code: 11>
2.1.3 :004 >
Probably this is a really stupid question, but I'm quite a beginner using Rails. Do I need to import some sort of "Context" (this seems unlikely, since Student seems to be properly resolved)? I'm using Rails 4.2.4.rc1 by the way.
Thanks in advance

Any chance at that point in the code Career isn't an AR, but some other class? That would at least explain why the methods don't exist.

Related

Migrate models between different environments in Rails

I am writing a script that will be in charge of transferring data from production db to a new production db.
There is one Rails app connecting to each database. In the new app we have made some migrations that change the schema (remove columns, etc)
I tried to do this:
rails console old
2.0.0p247 :004 > tag = Tag.last.dup
=> #<Tag id: nil, description: " views", account_id: 46, screenshotBase64: "", user_id: 1, created_at: nil, updated_at: nil>
2.0.0p247 :005 > ActiveRecord::Base.establish_connection(:development)
2.0.0p247 :006 > tag.save
ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'screenshotBase64' in 'field list
As we removed the screenshotBase64 in the new db, it does not work.
Is there a way to do that with Rails ? Delete attributes from Rails model before save ?
Is there a better way to transfer all data from a user linked through its associations between two databases (changing ids in the new db) ?
Please have a try with this code
tag_attributes = Tag.last.attributes.dup
%w(id screenshotBase64).map{|method| tag_attributes.delete method}
ActiveRecord::Base.establish_connection(:development)
tag = Tag.create(tag_attributes)

Trouble accessing column value rails console

I'm trying to access the integer stored in a column called totalVotes in my UserVotes table but keep getting a No Method Error
I have been trying to debug from the console:
1.9.3-p327 :006 > uservote = UserVote.where("soundcloud_id = 68061927")
UserVote Load (0.2ms) SELECT "user_votes".* FROM "user_votes" WHERE (soundcloud_id = 68061927)
=> [#<UserVote id: 5, user_id: "1", party_profile_id: "1", soundcloud_id: "68061927", totalVotes: 0, created_at: "2013-02-19 04:57:58", updated_at: "2013-02-19 04:57:58">]
Good so far...
1.9.3-p327 :007 > uservote.totalVotes
NoMethodError: undefined method `totalVotes' for #<ActiveRecord::Relation:0x007febb49ab350>
Then it breaks and I'm not sure why. What is the best way for me to access the totalVotes value?
your issue is you're calling .totalVotes to an AR Relation. call .first first then you should have no problem.
>> uservote = UserVote.where("soundcloud_id = 68061927").first
>> uservote.totalVotes

Active Record has_many generates sql with foreign key IS NULL

I don't expect a model with NULL as foreign key to belong to anything!
I have the following rails app, modelling ants and ant hills (inspired by Jozef).
$ rails -v
Rails 3.2.8
$ rails new ant_hill
$ cd ant_hill
Create the ant hill and ant models. An ant can belong to an ant hill and an ant hill can have many ants.
$ rails generate model AntHill name:string
$ rails generate model Ant name:string ant_hill_id:integer
$ vim app/models/ant.rb
$ cat app/models/ant.rb
class Ant < ActiveRecord::Base
belongs_to :ant_hill
end
$ vim app/models/ant_hill.rb
$ cat app/models/ant_hill.rb
class AntHill < ActiveRecord::Base
has_many :ants
end
$ rake db:migrate
== CreateAntHills: migrating =================================================
-- create_table(:ant_hills)
-> 0.0013s
== CreateAntHills: migrated (0.0016s) ========================================
== CreateAnts: migrating =====================================================
-- create_table(:ants)
-> 0.0035s
== CreateAnts: migrated (0.0037s) ============================================
Run the following code in a console.
$ rails c
Loading development environment (Rails 3.2.8)
Create a couple of ants, persisted, that don't belong to any ant hill.
1.9.2-p290 :001 > Ant.create! name: "August"
=> #<Ant id: 1, name: "August", ant_hill_id: nil, created_at: "2012-09-27 12:01:06", updated_at: "2012-09-27 12:01:06">
1.9.2-p290 :002 > Ant.create! name: "Bertil"
=> #<Ant id: 2, name: "Bertil", ant_hill_id: nil, created_at: "2012-09-27 12:01:13", updated_at: "2012-09-27 12:01:13">
Now instantiate an ant hill, but don't save it just yet.
1.9.2-p290 :003 > ant_hill = AntHill.new name: "Storkullen"
=> #<AntHill id: nil, name: "Storkullen", created_at: nil, updated_at: nil>
I expect this ant hill to not have any ants and it doesn't.
1.9.2-p290 :004 > ant_hill.ants
=> []
I still expect the ant hill to not have any ants but now it has two.
1.9.2-p290 :005 > ant_hill.ants.count
(0.1ms) SELECT COUNT(*) FROM "ants" WHERE "ants"."ant_hill_id" IS NULL
=> 2
Same here, it should never generate a query containing "IS NULL" when dealing with foreign keys. I mean "belongs_to NULL" can't belong to anything, right?
1.9.2-p290 :006 > ant_hill.ants.all
Ant Load (0.4ms) SELECT "ants".* FROM "ants" WHERE "ants"."ant_hill_id" IS NULL
=> [#<Ant id: 1, name: "August", ant_hill_id: nil, created_at: "2012-09-27 12:01:06", updated_at: "2012-09-27 12:01:06">, #<Ant id: 2, name: "Bertil", ant_hill_id: nil, created_at: "2012-09-27 12:01:13", updated_at: "2012-09-27 12:01:13">]
After it is persisted it behaves as expected.
1.9.2-p290 :007 > ant_hill.save!
=> true
1.9.2-p290 :008 > ant_hill.ants.count
(0.4ms) SELECT COUNT(*) FROM "ants" WHERE "ants"."ant_hill_id" = 1
=> 0
1.9.2-p290 :009 > ant_hill.ants.all
Ant Load (0.4ms) SELECT "ants".* FROM "ants" WHERE "ants"."ant_hill_id" = 1
=> []
Any insight? Is this the expected behavior?
While it seems counterintuitive, I think this behavior makes sense given your examples. Take ant_hill.ants.count for example. Count is an ActiveRecord query method that hits the database, and you're essentially asking ActiveRecord to give you all the ants that do not belong to an ant hill. Rails is simply letting you do something you should not be able to do, and not complaining about it. Should this be raising an exception instead? Possibly.
If you really want to know how many ants belong to this ant_hill object, you should be using size. It queries the object when not persisted or when the association is already loaded, and queries the database otherwise.
ant_hill.ants.size
One way you can get around this oddity is to make ant_hill_id a required field by validating its presence.
TL;DR Avoid using ActiveRecord query interface if parent object is not persisted to database.

Nested objects and collection size

I run into a weird issue since I upgraded to Rails 3.2.
My application have some objects managed with nested_forms, but when i try to reach a collection's size after having built a new nested object, the nested object is taken in count.
For ex.:
1.9.3p0 :004 > e = Expense.last
Expense Load (22.6ms) (...)
=> #<Expense id: 1, (...)
1.9.3p0 :005 > e.comments.size
(0.3ms) SELECT COUNT(*) (...)
=> 0
1.9.3p0 :006 > e.comments.build
=> #<Comment id: nil, content: nil, commentable_id: 1, commentable_type: "Expense", created_at: nil, updated_at: nil, creator_id: nil>
1.9.3p0 :007 > e.comments.size
=> 1
In this case, I expect the e.expense.size to return 0 since the Commentobject has not been saved yet.
Building the comment creates ... 1 comment. It doesn't exist in the database (yet) so e.commment.count would return 0, but it exists in the application, so size returns 1. So that sort of makes sense.
But I do see there's a little potentially unexpected result here. If a comment doesn't exist in memory, it looks like Rails checks with the DB (the SELECT COUNT(*)...), whereas if it finds one in memory it does not.
I wonder what would happen if you had several existing comments already, then checked e.comments.size in that case?
Which version of Rails were you coming from that worked differently?

Rails: Some seeds don't appear to be saving

It appears some of my seeds are not saving. For starters, I will show a console session so you can see that the 'instructor_id' is indeed being set in the console, but not when I seed.
ruby-1.9.2-p180 :015 > c = Course.find 2
Course Load (1.6ms) SELECT "courses".* FROM "courses" WHERE "courses"."id" = $1 LIMIT 1 [["id", 2]]
=> #<Course id: 2, name: "Microcomputers II Lab", course_code: "CE-420L", instructor_id: nil, school_id: nil, created_at: "2011-06-04 19:40:32", updated_at: "2011-06-04 19:40:32">
ruby-1.9.2-p180 :016 > c.instructor = Instructor.first
Instructor Load (0.6ms) SELECT "instructors".* FROM "instructors" LIMIT 1
=> #<Instructor id: 1, name: "Instructor Name", created_at: "2011-06-04 19:40:32", updated_at: "2011-06-04 19:40:32">
ruby-1.9.2-p180 :017 > c
=> #<Course id: 2, name: "Microcomputers II Lab", course_code: "CE-420L", instructor_id: 1, school_id: nil, created_at: "2011-06-04 19:40:32", updated_at: "2011-06-04 19:40:32">
From looking at the console, you can see that when I call c.instructor = Instructor.first, it is correctly setting my instructor_id.
Now, in the seeds file I have variables. (This is just a snippet)
### Instructors ###
puts "Creating Instructors"
instructor_1 = Instructor.find_or_create_by_name("Instructor Name")
### Courses ###
puts "Creating Courses"
ce420L = Course.find_or_create_by_name("Microcomputers II Lab", :course_code => "CE-420L")
### Add the Instructor to the Course ###
puts "Adding an Instructor to the Courses"
ce420L.instructor = instructor_1
But when I run the seeds using 'rake db:seed', it is correctly creating all of my models, and most of my relationships. But it is not setting the instructor properly.
Thoughts?
EDIT:
Just tried:
ce420 = Course.find_or_initialize_by_name("Microcomputers II")
ce420.instructor_id = instructor_1.id
ce420.save!
And it did not save my instructor.
Here are my models.
class Instructor < ActiveRecord::Base
### ASSOCIATIONS ###
has_many :courses
end
class Course < ActiveRecord::Base
belongs_to :instructor
end
Did you run...
ce420L.save!
... after assigning the instructor?
Much faster to do this:
### Courses ###
puts "Creating Courses belonging to Instructor 1"
ce420L = Course.find_or_initialize_by_name("Microcomputers II Lab") :course_code => "CE-420L")
ce420L.instructor_id = instructor_1.id
ce420L.save
Note the following:
You had an errant comma after your find_or_create on ce420L.
Doing the assignment together with the course creation prevents the system from validating and saving ce420L twice.
You can try assigning the specific ID as I did, i.e. ce420L.instructor_id = ...
If this doesn't work, check your Instructor Model to ensure you don't have any callbacks getting in the way.

Resources