Rails : double association with same Model - ruby-on-rails

I created a double "Synonym" association with the same Word model as following:
class Synonym < ApplicationRecord
belongs_to :word_origin, :class_name => "Word"
belongs_to :word_synonym, :class_name => "Word"
end
Here is my Word model:
class Word < ApplicationRecord
has_many :word_synonyms, :class_name => 'Word', :foreign_key => 'word_synonym_id', dependent: :destroy
has_many :word_origins, :class_name => 'Word', :foreign_key => 'word_origin_id', dependent: :destroy
end
However, when I try to delete a word, I get the following error:
ActiveRecord::StatementInvalid (PG::UndefinedColumn: ERROR: column
words.word_synonym_id does not exist)
Any idea what's wrong with my double association? Thanks.
EDIT: here is the schema of Word and Synonym
create_table "words", force: :cascade do |t|
t.string "content"
t.string "slug"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["content"], name: "index_words_on_content", opclass: :gin_trgm_ops, using: :gin
end
create_table "synonyms", force: :cascade do |t|
t.bigint "word_origin_id"
t.bigint "word_synonym_id"
t.index ["word_origin_id"], name: "index_synonyms_on_word_origin_id"
t.index ["word_synonym_id"], name: "index_synonyms_on_word_synonym_id"
end

Word is referencing itself without the needed columns. You have to change the line to be
has_many :word_synonyms, class_name: 'Synonym',
foreign_key: 'word_synonym_id', dependent: :destroy
has_many :word_origins, class_name: 'Synonym',
foreign_key: 'word_origin_id', dependent: :destroy

Related

Rails - Polymorphic has_many :through with model not building on create

My has_many :through model (Posting) is not building an object on creation of the primary associated object (Post). How can I build the relationship on creation?
Models:
class Post
has_many :postings, dependent: :destroy
has_many :products, through: :postings, source: :postable, source_type: "Product"
has_many :Items, through: :postings, source: :postable, source_type: "Item"
end
class Posting
belongs_to :postable, polymorphic: true
belongs_to :post
end
class Product
has_many :postings, as: :postable
has_many :posts, through: :postings
end
class Item
has_many :postings, as: :postable
has_many :posts, through: :postings
end
Schema:
create_table "postings", force: :cascade do |t|
t.bigint "postable_id"
t.string "postable_type"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.bigint "post_id"
t.index ["post_id"], name: "index_postings_on_post_id"
end
create_table "posts", force: :cascade do |t|
t.string "title"
t.string "slug"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Console:
Post.create(title: "Foo", product_id:3)
Traceback (most recent call last):
1: from (irb):12
ActiveModel::UnknownAttributeError (unknown attribute 'product_id' for Post.)
Appreciate any tips!

Unable to count records for associated model NoMethodError

I tried to multiple ways to get the count of all job applications for the job model, that an employer has. When it comes to one job in particular (job.job_applications.count), it works. You can actually count the applications for that job in question. When you try to sum all job applications for all jobs. I may have overlooked something while setting up the relationships. I receive the error below:
line of code that breaks: <%= current_employer.jobs.job_applications.count %>
undefined method job_applications' for #<Job::ActiveRecord_Associations_CollectionProxy:0x0000000011066998>
The code that I wrote beforehand, is below:
schema
job
create_table "jobs", force: :cascade do |t|
t.string "job_title"
t.text "required_exp"
t.text "job_description"
t.text "job_requirements"
t.bigint "employer_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "slug"
t.bigint "visit_id"
t.index ["employer_id"], name: "index_jobs_on_employer_id"
t.index ["slug"], name: "index_jobs_on_slug", unique: true
end
job applications
create_table "job_applications", force: :cascade do |t|
t.bigint "user_id"
t.string "user_resume_link"
t.string "user_contact_time"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "user_first_name"
t.string "user_last_name"
t.bigint "job_id"
t.index ["job_id"], name: "index_job_applications_on_job_id"
t.index ["user_id"], name: "index_job_applications_on_user_id"
end
job.rb
class Job < ApplicationRecord
belongs_to :employer
has_many :job_applications, dependent: :destroy
has_one :job_category
end
job_application.rb
class JobApplication < ApplicationRecord
belongs_to :user
belongs_to :job
end
employer.rb
class Employer < ApplicationRecord
has_many :jobs, :dependent => :destroy
end
user.rb
class User < ApplicationRecord
has_many :job_applications, dependent: :destroy
has_many :jobs, :through => :job_applications
end
class Employer < ApplicationRecord
has_many :jobs, :dependent => :destroy
has_many :job_applications, through: :jobs
end
And then just call current_employer.job_applications.count

Ruby on Rails associations for has_many, through, source returns NoMethodError

I have three models user.rb, vote.rb, and event.rb
User
has_many :votes, foreign_key: 'voter_id', dependent: :destroy
has_many :voting, through: :votes, source: :voted
Vote
belongs_to :voter, class_name: "User"
belongs_to :voted, class_name: "Event"
Event
has_many :votes, foreign_key: 'voted_id', dependent: :destroy
has_many :voters, through: :votes, source: :voter
For some reason, if I call User.first.voting I get: NoMethodError: undefined method 'voted' for #<User:0x00007fbc56d069d8>
Anybody know why? I have googled a few other questions regarding this topic and I don't see where I am going wrong.
If you're on rails 5, I made a working code:
User
has_many :votes, foreign_key: 'voter_id', dependent: :destroy
has_many :voting, through: :votes, source: :voted
Event
has_many :votes, foreign_key: 'voted_id', dependent: :destroy
has_many :voters, through: :votes, source: :voter
Vote
belongs_to :voter, class_name: "User", optional: true
belongs_to :voted, class_name: "Event", optional: true
Schema
create_table "events", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "votes", force: :cascade do |t|
t.integer "voter_id"
t.integer "voted_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
To test (rails console)
> User.create
> Event.create
> Vote.create(:voter_id => 1, :voted_id => 1)
> User.first.voting
=> #<ActiveRecord::Associations::CollectionProxy
> User.first.voting.first # to get event instance
=> #<Event ...
Hope this helps!

how to update schema after adding "accepts_nested_attributes_for" to a model

here is my model
class Lineup < ApplicationRecord
has_many :artists
accepts_nested_attributes_for :artists
belongs_to :event
end
class Artist < ApplicationRecord
has_many :events, :through => :lineups
has_many :lineups
end
when running this in the console
Lineup.new(artists_attributes: [{artist_id: 1}, {artist_id: 2}])
the error is ActiveModel::UnknownAttributeError: unknown attribute 'artists_attributes' for Lineup. Obviously, I can't just drop something like that into a model and expect any changes to be from that alone. Do I need to run a migration for this? If so, what needs to be in it?
schema:
create_table "artists", force: :cascade do |t|
t.string "name"
t.text "bio"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "lineup_id"
t.integer "event_id"
end
add_index "artists", ["event_id"], name: "index_artists_on_event_id", using: :btree
add_index "artists", ["lineup_id"], name: "index_artists_on_lineup_id", using: :btree
create_table "lineups", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "artist_id"
t.integer "event_id"
end
add_index "lineups", ["artist_id"], name: "index_lineups_on_artist_id", using: :btree
add_index "lineups", ["event_id"], name: "index_lineups_on_event_id", using: :btree
I would set it up like this
schema
table Lineup
...
table Artist
...
table LineupArtists
lineup_id: Integer
artist_id: Integer
models
class Artist < ApplicationRecord
has_many :lineup_artists, dependent: :destroy
has_many :lineups, through: :lineup_artists
end
class LineupArtist < ApplicationRecord
belongs_to :lineup
belongs_to :artist
accepts_nested_attributes_for :lineup
end
class Lineup < ApplicationRecord
has_many :lineup_artists, inverse_of: :lineup, dependent: :destroy
has_many :artists, through: lineup_artists
accepts_nested_attributes_for :lineup_artists
end
The way you currently have it (with Artists having a lineup_id and Lineups having an artist_id) each model can only have one of the other (i.e. an Artist can have one lineup and vise versa). A join table gives the ability to have a many-to-many relationship.
Setting up nested attributes is a little trickier with a many-to-many but I believe what I posted should cover it. If not got some of the weirder bits from this post (https://robots.thoughtbot.com/accepts-nested-attributes-for-with-has-many-through). Hope this helps.
Try to replace line:
has_many :artists
With this one:
has_many :artists, foreign_key: "lineup_id"

How do I write this has_many_to_many dependency?

I am trying to create a has many to many relationship between a Goal model. A goal can have dependent goals and a goal can have others goals that rely on it.
So far I have come up with the below, but it does not seem to be working.
class Goal < ActiveRecord::Base
belongs_to :goal_status
belongs_to :goal_type
has_many :users, through: :user_goals
has_many :user_goals
has_many :dependers, class_name: 'GoalDependency', foreign_key: :dependee_id
has_many :dependees, class_name: 'GoalDependency', foreign_key: :depender_id
has_many :dependencies, through: :dependees
has_many :depending, through: :dependers
validates_presence_of :goal_status_id, :goal_type_id
end
class GoalDependency < ActiveRecord::Base
belongs_to :dependee, class_name: 'Goal', foreign_key: 'dependee_id'
belongs_to :depender, class_name: 'Goal', foreign_key: 'depender_id'
end
Schema
create_table "goal_dependencies", force: :cascade do |t|
t.integer "dependee_id"
t.integer "depender_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "goals", force: :cascade do |t|
t.integer "goal_status_id"
t.integer "goal_type_id"
t.string "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
I am getting the error
Could not find the source association(s) "dependency" or :dependencies in model GoalDependency. Try 'has_many :dependencies, :through => :dependees, :source => <name>'. Is it one of dependee or depender?
I have tried putting in a couple of different values as the source, but nothing is working. I am not really familiar that much with using source.
I would guess this is possible in rails. Any ideas?
After taking #Pavan's advice I changed the language around and managed to get it working that way. See the code below.
class Goal < ActiveRecord::Base
belongs_to :goal_status
belongs_to :goal_type
has_many :users, through: :user_goals
has_many :user_goals
has_many :parent_goals, class_name: 'GoalDependency', foreign_key: :parent_id
has_many :child_goals, class_name: 'GoalDependency', foreign_key: :child_id
has_many :children, through: :child_goals
has_many :parents, through: :parent_goals
validates_presence_of :goal_status_id, :goal_type_id
end
class GoalDependency < ActiveRecord::Base
belongs_to :parent, class_name: 'Goal', foreign_key: 'parent_id'
belongs_to :child, class_name: 'Goal', foreign_key: 'child_id'
end
Schema
create_table "goals", force: :cascade do |t|
t.integer "goal_status_id"
t.integer "goal_type_id"
t.string "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "goal_dependencies", force: :cascade do |t|
t.integer "parent_id"
t.integer "child_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end

Resources