Rails 3.2.12 uninitialized constant error - ruby-on-rails

I've been beating my head against my desk all afternoon trying to get past an uninitialized constant error, but can't seem to get beyond it. I have the following models:
sub_award.rb
class SubAward < ActiveRecord::Base
has_many :sub_awards_colleges, foreign_key: [:award_id, :sub_id]
has_many :colleges, through: :sub_awards_colleges
end
sub_awards_colleges.rb
class SubAwardsCollege < ActiveRecord::Base
belongs_to :sub_award, foreign_key: [:award_id, :sub_id]
belongs_to :college
end
colleges.rb
class College < ActiveRecord::Base
has_many :sub_awards_colleges, foreign_key: [:award_id, :sub_id]
has_many :sub_awards, through: :sub_awards_colleges
end
When I attempt to call sub_award.colleges from my view I get the error:
ActionView::Template::Error (uninitialized constant SubAward::SubAwardsCollege)
I believe I have followed all the proper rails conventions and I have other associations within the sub_award model that I set up the same and are working fine. The tables look like (unrelated attribute omitted):
mysql> DESCRIBE sub_awards_colleges;
+------------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| award_id | int(11) | NO | | NULL | |
| sub_id | int(11) | NO | | NULL | |
| college_id | int(11) | NO | MUL | NULL | |
+------------+---------+------+-----+---------+----------------+
mysql> DESCRIBE sub_awards;
+--------------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------------------+--------------+------+-----+---------+-------+
| award_id | int(11) | NO | | NULL | |
| sub_id | int(11) | NO | | NULL | |
mysql> DESCRIBE colleges;
+-------------------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------------+---------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
Any help is appreciated and please let me know if you'd like me to provide more information. Thanks!

You might have missed to place your sub_awards_colleges.rb file in app/models !
I had a similar problem once.
Also why are award_id ans sub_id columns in sub_awards_colleges, As far as I guess, you have a mapping table which should map it to colleges. and there is no use of college_id in mapping, all the mapping is based of award_id and sub_id. This is pretty confusing. You might want to have a look at your mappings once again.

I solved my issue, but I'm still not entirely sure what the problem was. To solve I blew away the existing sub_awards_college.rb file. I then created a new migration to drop the sub_awards_colleges table and re-create it and generated a fresh sub_awards_college.rb model. I re-populated the sub_awards_college.rb file with my associations:
belongs_to :sub_award, foreign_key: [:award_id, :sub_id]
belongs_to :college, class_name: "College"
adding the class_name option (although it shouldn't be necessary according to conventions) and also added additional parameters to the sub_award.rb associations so it read as:
has_many :sub_awards_colleges, foreign_key: [:award_id, :sub_id], source: :sub_awards_colleges, class_name: "SubAwardsCollege"
has_many :colleges, through: :sub_awards_colleges, after_add: :invalidate_matching, after_remove: :invalidate_matching, source: :college, class_name: "College"
again, shouldn't be necessary according to conventions, but restarted my app and it's now working. So not exactly sure what my problem was, maybe there was something hokey in the database regarding how my tables were set up so they weren't aligning properly with the models, but it's working now and thank you for taking the time to review and provide comments.

Related

Rails: Build Association when id Method is Non-standard

I'm trying to build a JobReport model that holds the return value from GoodJob jobs. The two fields I could build an association on, id and active_job_id, are problematic. The id field is set to return the active_job_id in the Job class:
# from good_job-3.12.1/app/models/good_job/job.rb
def id
active_job_id
end
The good_jobs.active_job_id field has no uniqueness constraint, and setting it as a foreign key throws a postgres error.
How can I link these two tables?
Here's the migration I'm using to create the job_reports table:
class CreateJobReports < ActiveRecord::Migration[7.0]
def change
create_table :job_reports do |t|
t.text :report
t.uuid :good_job_id
t.timestamps
end
add_foreign_key :job_reports, :good_jobs, column: :good_job_id, primary_key: :id
end
end
My JobReport model:
class JobReport < ApplicationRecord
belongs_to :good_job, class_name: 'GoodJob::Job', foreign_key: 'id'
end
And my good_job.rb initializer contains:
GoodJob::Job.class_eval do
has_one :job_report, dependent: :destroy
end
When I create a JobReport, tie it to a Job, and save it, postgres complains that the id doesn't exist in good_jobs, because it's trying to use the active_job_id:
irb(main):001:0> jr = JobReport.new; gj = GoodJob::Job.last
=>
#<GoodJob::Job:0x00007ff6950cda30
...
irb(main):002:0> jr.good_job = gj
=>
#<GoodJob::Job:0x00007ff6950cda30
...
irb(main):003:0> jr.save
/usr/local/bundle/gems/activerecord-7.0.4.1/lib/active_record/connection_adapters/postgresql_adapter.rb:768:in `exec_params': PG::ForeignKeyViolation: ERROR: insert or update on table "job_reports" violates foreign key constraint "fk_rails_6135bfd69e" (ActiveRecord::InvalidForeignKey)
DETAIL: Key (good_job_id)=(fdc02e75-a06a-4727-b790-9a846f61ed7d) is not present in table "good_jobs".
/usr/local/bundle/gems/activerecord-7.0.4.1/lib/active_record/connection_adapters/postgresql_adapter.rb:768:in `exec_params': ERROR: insert or update on table "job_reports" violates foreign key constraint "fk_rails_6135bfd69e" (PG::ForeignKeyViolation)
DETAIL: Key (good_job_id)=(fdc02e75-a06a-4727-b790-9a846f61ed7d) is not present in table "good_jobs".
irb(main):004:0> gj.id
=> "fdc02e75-a06a-4727-b790-9a846f61ed7d"
irb(main):005:0> gj.active_job_id
=> "fdc02e75-a06a-4727-b790-9a846f61ed7d"
irb(main):006:0> gj.attributes["id"]
=> "edc27b66-975d-4017-a09f-2d0cec332a0c"
As I mentioned before, if I give up on the ID column and switch to the active_job_id column, postgres says I can't use it as a foreign key b/c there's no uniqueness constraint. Sure, I could edit the GoodJob tables, but I'd prefer to use the drop-in form of the gem without tampering with it for upgrades and whatnot down the road.
Edit: I implemented Max's suggestion, but it's still trying to use the active_job_id column of the good_jobs table instead of the id column.
class JobReport < ApplicationRecord
belongs_to :good_job, class_name: 'GoodJob::Job', foreign_key: 'good_job_id', primary_key: 'id'
end
irb(main):010:0> jr = JobReport.new; gj = GoodJob::Job.last
=>
#<GoodJob::Job:0x00007f70ec430918
...
irb(main):011:0> jr.good_job = gj
=>
#<GoodJob::Job:0x00007f70ec430918
...
irb(main):012:0> jr.save
/usr/local/bundle/gems/activerecord-7.0.4.1/lib/active_record/connection_adapters/postgresql_adapter.rb:768:in `exec_params': PG::ForeignKeyViolation: ERROR: insert or update on table "job_reports" violates foreign key constraint "fk_rails_6135bfd69e" (ActiveRecord::InvalidForeignKey)
DETAIL: Key (good_job_id)=(fdc02e75-a06a-4727-b790-9a846f61ed7d) is not present in table "good_jobs".
/usr/local/bundle/gems/activerecord-7.0.4.1/lib/active_record/connection_adapters/postgresql_adapter.rb:768:in `exec_params': ERROR: insert or update on table "job_reports" violates foreign key constraint "fk_rails_6135bfd69e" (PG::ForeignKeyViolation)
DETAIL: Key (good_job_id)=(fdc02e75-a06a-4727-b790-9a846f61ed7d) is not present in table "good_jobs".
irb(main):013:0> gj.id
=> "fdc02e75-a06a-4727-b790-9a846f61ed7d"
irb(main):014:0> gj.active_job_id
=> "fdc02e75-a06a-4727-b790-9a846f61ed7d"
irb(main):015:0> gj.attributes['id']
=> "edc27b66-975d-4017-a09f-2d0cec332a0c"
Here's the schema of the two tables:
development=# \d good_jobs
Table "public.good_jobs"
Column | Type | Collation | Nullable | Default
---------------------+--------------------------------+-----------+----------+-------------------
id | uuid | | not null | gen_random_uuid()
queue_name | text | | |
priority | integer | | |
serialized_params | jsonb | | |
scheduled_at | timestamp(6) without time zone | | |
performed_at | timestamp(6) without time zone | | |
finished_at | timestamp(6) without time zone | | |
error | text | | |
created_at | timestamp(6) without time zone | | not null |
updated_at | timestamp(6) without time zone | | not null |
active_job_id | uuid | | |
concurrency_key | text | | |
cron_key | text | | |
retried_good_job_id | uuid | | |
cron_at | timestamp(6) without time zone | | |
batch_id | uuid | | |
batch_callback_id | uuid | | |
Indexes:
"good_jobs_pkey" PRIMARY KEY, btree (id)
"index_good_jobs_on_cron_key_and_cron_at" UNIQUE, btree (cron_key, cron_at)
"index_good_jobs_jobs_on_finished_at" btree (finished_at) WHERE retried_good_job_id IS NULL AND finished_at IS NOT NULL
"index_good_jobs_jobs_on_priority_created_at_when_unfinished" btree (priority DESC NULLS LAST, created_at) WHERE finished_at IS NULL
"index_good_jobs_on_active_job_id" btree (active_job_id)
"index_good_jobs_on_active_job_id_and_created_at" btree (active_job_id, created_at)
"index_good_jobs_on_batch_callback_id" btree (batch_callback_id) WHERE batch_callback_id IS NOT NULL
"index_good_jobs_on_batch_id" btree (batch_id) WHERE batch_id IS NOT NULL
"index_good_jobs_on_concurrency_key_when_unfinished" btree (concurrency_key) WHERE finished_at IS NULL
"index_good_jobs_on_cron_key_and_created_at" btree (cron_key, created_at)
"index_good_jobs_on_queue_name_and_scheduled_at" btree (queue_name, scheduled_at) WHERE finished_at IS NULL
"index_good_jobs_on_scheduled_at" btree (scheduled_at) WHERE finished_at IS NULL
Referenced by:
TABLE "job_reports" CONSTRAINT "fk_rails_6135bfd69e" FOREIGN KEY (good_job_id) REFERENCES good_jobs(id)
development=# \d job_reports
Table "public.job_reports"
Column | Type | Collation | Nullable | Default
-------------+--------------------------------+-----------+----------+-----------------------------------------
id | bigint | | not null | nextval('job_reports_id_seq'::regclass)
report | text | | |
good_job_id | uuid | | |
created_at | timestamp(6) without time zone | | not null |
updated_at | timestamp(6) without time zone | | not null |
Indexes:
"job_reports_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"fk_rails_6135bfd69e" FOREIGN KEY (good_job_id) REFERENCES good_jobs(id)

How to reject blank before_save callback rails?

i want to reject blank param with model callback
Schema:
Interviews
+----------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+-------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| note | varchar(50) | YES | | NULL | |
| interview_at | datetime | NO | | NULL | |
| created_at | datetime | NO | | NULL | |
| updated_at | datetime | NO | | NULL | |
+----------------+-------------+------+-----+---------+----------------+
Controller:
def interviews
return [] unless params[:interviews]
parse_params(:interviews).map do |interview|
Interview.find_or_initialize_by( interview }) )
end
end
Model:
class Interview < ApplicationRecord
before_save :remove_blank
def remove_blank
#new_record = false if interview_at.blank?
end
end
Example:
Input:
Interview 1( interview_at: '2019-09-15 22:00', note: 'abc')
Interview 2( interview_at: '', note: 'bcd')
Output:
Interview 1( interview_at: 2019-09-15 22:00, note: 'abc')
Interview 2( interview_at: 2019-09-15 22:00, note: 'abc')
before_save return wrong attribute when i create. How can i fix that?
Thank you for help
You can give this a try, you would want to create a validation, this will prevent the record from being saved and make the model record will return false when you call valid? on it.
class Interview < ApplicationRecord
validate :interview_at_not_blank
def interview_at_not_blank
errors.add(:interview_at, :blank, message: "cannot be blank") unless interview_at.blank?
end
end

ActiveRecord associations with two different models

I'm having a tough time wrapping my head around how I should be configuring my tables + associations.
I have a Lawsuit model. A lawsuit has_many parties (defendants, plaintiffs, attorneys, etc.). A party, in turn, can either be a Person or a Company. Ultimately, I want to be able to get:
A person’s lawsuits (#person.lawsuits);
A company’s lawsuits (#company.lawsuits); and
A lawsuit’s parties (#lawsuit.parties), which can be either people or companies.
This is how I have my tables + models set up currently:
people
| id | fname | lname | date_of_birth |
| -- | ------ | ----- | ------------- |
| 1 | John | Smith | 1974-02-04 |
| 2 | George | Glass | 1963-07-29 |
companies
| id | name | duns | ticker | address |
| -- | --------- | --------- | ------ | ------------ |
| 1 | Acme Inc. | 239423243 | ACME | 123 Main St. |
lawsuits
| id | jurisdiction | court | case_no | title |
| -- | ------------ | ----- | ---------- | --------------------------- |
| 1 | federal | SDNY | 18-CV-1234 | Smith v. Glass, Acme, et al |
lawsuit_parties
| id | lawsuit_id | person_id | company_id | role |
| -- | ---------- | --------- | ---------- | --------- |
| 1 | 1 | 1 | | plaintiff |
| 2 | 1 | 2 | | defendant |
| 3 | 1 | | 1 | defendant |
# models/lawsuit.rb:
class Lawsuit < ApplicationRecord
has_many :lawsuit_parties
def parties
self.lawsuit_parties
end
def defendants
self.parties(where(lawsuit_parties: {role: 'defendant'})
end
def plaintiffs
self.parties(where(lawsuit_parties: {role: 'plaintiff'})
end
def attorneys
self.parties(where(lawsuit_parties: {role: 'attorney'})
end
end
# models/lawsuit_party.rb
class LawsuitParty < ApplicationRecord
belongs_to :person
belongs_to :company
end
# models/person.rb
class Person < ApplicationRecord
has_many :lawsuit_parties
has_many :lawsuits, through: :lawsuit_parties
end
# models/company.rb
class Company < ApplicationRecord
has_many :lawsuit_parties
has_many :lawsuits, through: :lawsuit_parties
end
Any help you would be much appreciated…
You're on the right track, but you'll need to introduce a polymorphic relationship onto your Join Model to get this type of modeling to work. An Enum can handle differentiating between Defendants and Plaintiffs, as well as provide several scopes/methods you're asking for for free.
class LawsuitParty < ApplicationRecord
belongs_to :lawsuit
belongs_to :partiable, polymorphic: true
enum role: [:defendant, :plaintiff]
end
You'll need to write a migration to change your lawsuit_parties table to the following columns (all Rails convention names):
partiable_id = Integer
partiable_type = String
role = String
lawsuit_parties
| id | lawsuit_id | partiable_id | partiable_type | role |
| -- | ---------- | ------------ | -------------- | ----------|
| 1 | 1 | 1 | Person | defendant |
| 2 | 1 | 2 | Company | plaintiff |
| 3 | 1 | 1 | Company | defendant |
Next, tell Rails that Person and Company records are associated with many Lawsuit's using has_many's :as option.
class Person < ApplicationRecord
has_many :lawsuit_parties, as: :partiable
has_many :lawsuits, through: :lawsuit_parties
end
Add the same has_many :lawsuit_parties, as: :partiable to Company, or any other models that may come later (i.e. Judge or JuryMember).
Once you have a LawsuitParty setup like this, you should be all set.

How to using "where" to dynamic build realation

Sry for broken english
I have 2 table fruits and berries and 2 model fruit and berry, both id are primary key, berries's id is a foreign key of fruits.
The meaning is if fruit's attr is "berry" then this fruit will have hp, atk, def. other just a normal fruit, they don't have hp, atk, def.
i'm tring "where" but not work, and i have no idea to add foreign key to migrate file
it's any solutions can solve this realation
fruits
+-----+------------+-----------+
| id | name | attr |
+-----+------------+-----------+
| 123 | Blueberry | berry |
| 932 | Apple | not berry |
| 429 | Banana | not berry |
| 563 | Strawberry | berry |
+-----+------------+-----------+
berries
+-----+----+-----+-----+
| id | hp | atk | def |
+-----+----+-----+-----+
| 123 | 15 | 5 | 5 |
| 563 | 7 | 10 | 3 |
+-----+----+-----+-----+
Fruit
class Fruit < ActiveRecord::Base
has_one :berry, -> { where attr: "berry"}, foreign_key: 'id'
end
Berry
class Berry < ActiveRecord::Base
belongs_to :fruit
end
First of all bannanas are considered berries... sometimes
There are at least 2 ways of doing this
Single Table Inheritance (STI)
Multiple Table Inheritance
In STI you only create the fruits table in the database, but add all the columns the Berry class will need. Even if this method will leave many blank spaces in the DB where fruits aren't berries, I recommend it because it is pretty straight forward and supported by rails. To use it change your attr column to type and add the hp, atk and def columns in a migration:
rails g migration AddAttrsToFruit hp:integer atk:integer def:integer
rails g migration ChangeAttrToType
Since the migration generator doesn't do magic like when the migration starts with the word Change as it does with Add, you have to edit the change function in the migration it creates to look like this:
rename_column :fruits, :attr, :type
Then change your Berry class to inherit from Fruit instead of ActiveRecord::Base
class Berry < ActiveRecord::Base
belongs_to :fruit
end
Now when you create a Berry
Berry.create(name: 'Coconut', hp:100, atk:5, def:999)
Rails creates a the record in the Fruit table with all the attributes filed in:
#<ActiveRecord::Relation [#<Berry id: 1, name: nil, type: "Berry", created_at: "2015-10-14 02:38:09", updated_at: "2015-10-14 02:38:09", hp: 1, atk: nil, def: nil>]>
For MTI you can read the link.
Good luck :)
Great answer from robertoplancarte - to explain a little more simply for you, you're looking to use a has_many/belongs_to relationship:
#app/models/fruit.rb
class Fruit < ActiveRecord::Base
has_many :berries
end
#app/models/berry.rb
class Berry < ActiveRecord::Base
belongs_to :fruit
end
You can set it up in your database as follows:
#fruits
+-----+------------+-----------+
| id | name | attr |
+-----+------------+-----------+
| 123 | Blueberry | berry |
| 932 | Apple | not berry |
| 429 | Banana | not berry |
| 563 | Strawberry | berry |
+-----+------------+-----------+
#berries
+-----+----------+----+-----+-----+
| id | fruit_id | hp | atk | def |
+-----+----------+----+-----+-----+
| 1 | 123 | 15 | 5 | 5 |
| 2 | 932 | 10 | 3 | x |
+-----+----+-----+----+-----+-----+
This will allow you to call...
#fruit = Fruit.find params[:id]
#fruit.berries
What robertoplancarte was saying was your current setup is pretty weak:
You're identifying which "fruit" is a berry manually
You're then populating another model with data which could be put into the first
The way around this is to use something called an STI - Single Table Inheritance.
This is a Railsy way to use a single model to define multiple types of data:
#app/models/fruit.rb
class Fruit < ActiveRecord::Base
#columns id | type | name | hp | atk | def | created_at | updated_at
end
#app/models/berry.rb
class Berry < Fruit
end
This will give you the ability to call:
#berry = Berry.find x
This is more appropriate for your requirements; is somewhat advanced, but nothing a question on StackOverflow would be defeated by.

Is there an activerecord relationship to solve this problem?

I can't seem to wrap my head around this. I have three tables:
mysql> desc users;
+----------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| username | varchar(255) | YES | | NULL | |
+----------------------+--------------+------+-----+---------+----------------+
mysql> desc mentions;
+------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| message_id | int(11) | YES | | NULL | |
| mentionable_type | varchar(255) | YES | | NULL | |
| mentionable_id | int(11) | YES | | NULL | |
+------------------+--------------+------+-----+---------+----------------+
mysql> desc messages;
+------------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+----------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| body | text | YES | | NULL | |
| user_id | int(11) | YES | | NULL | |
+------------+----------+------+-----+---------+----------------+
And the following relationships:
class User < ActiveRecord::Base
has_many :messages
end
class Message < ActiveRecord::Base
belongs_to :user
has_many :mentions
end
class Mention < ActiveRecord::Base
belongs_to :mentionable, :polymorphic => true
belongs_to :message
end
I'm not sure if I'm using it correctly, but I used the polymorphic relationship in Mention because mentionable_type could be 'User' or 'Group'. I've left the Group stuff out of this post as it's not related to this question.
When a user creates a Message, their user_id is stored in the messages table. I can easily return a list of a user's "authored" messages with:
current_user.messages
Similar to a tweet, the message's body may, or may not, contain mentions of n users or groups. When the message "I'm having lunch with #userA, #userB, and #groupX." is created, the body would be parsed and those three "mentions" would be created as well.
I can easily return all of a user's "mentions" with:
current_user.mentions
If I want to see the message of a mention, I can do:
mention = current_user.mentions.first
mention.message
What I can't seeem to figure out is a clean way to combine the two and get a list of messages that a user created AND were mentioned in. Any ideas?
I your User model, this line should be present for polymorphic relationships.
class User
has_many :messages
has_many :mentions, :as => :mentionable
end
And try this:
user_id = 10
#messages = Message.find(:all, :joins => [:mentions],
:conditions => ['messages.user_id = ?', user_id])

Resources